From 9cf069f88ba43931c46b245f567b0f8371a6067c Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Oct 2014 15:07:44 -0400 Subject: curl: Move sources back into upstream layout Update our build files as needed to compensate. --- Utilities/cm_curl.h | 2 +- Utilities/cmcurl/CMakeLists.txt | 138 +- Utilities/cmcurl/amigaos.c | 74 - Utilities/cmcurl/amigaos.h | 58 - Utilities/cmcurl/arpa_telnet.h | 101 - Utilities/cmcurl/base64.c | 366 --- Utilities/cmcurl/base64.h | 28 - Utilities/cmcurl/ca-bundle.h | 1 - Utilities/cmcurl/connect.c | 905 ------ Utilities/cmcurl/connect.h | 46 - Utilities/cmcurl/content_encoding.c | 424 --- Utilities/cmcurl/content_encoding.h | 41 - Utilities/cmcurl/cookie.c | 1019 ------- Utilities/cmcurl/cookie.h | 107 - Utilities/cmcurl/curl/curl.h | 1644 ----------- Utilities/cmcurl/curl/curlver.h | 56 - Utilities/cmcurl/curl/easy.h | 81 - Utilities/cmcurl/curl/mprintf.h | 80 - Utilities/cmcurl/curl/multi.h | 327 -- Utilities/cmcurl/curl/stdcheaders.h | 34 - Utilities/cmcurl/curl/types.h | 1 - Utilities/cmcurl/curlx.h | 107 - Utilities/cmcurl/dict.c | 280 -- Utilities/cmcurl/dict.h | 30 - Utilities/cmcurl/easy.c | 895 ------ Utilities/cmcurl/easyif.h | 40 - Utilities/cmcurl/escape.c | 181 -- Utilities/cmcurl/escape.h | 30 - Utilities/cmcurl/file.c | 407 --- Utilities/cmcurl/file.h | 31 - Utilities/cmcurl/formdata.c | 1694 ----------- Utilities/cmcurl/formdata.h | 97 - Utilities/cmcurl/ftp.c | 3865 ------------------------ Utilities/cmcurl/ftp.h | 43 - Utilities/cmcurl/getenv.c | 69 - Utilities/cmcurl/getinfo.c | 234 -- Utilities/cmcurl/getinfo.h | 28 - Utilities/cmcurl/gtls.c | 640 ---- Utilities/cmcurl/gtls.h | 46 - Utilities/cmcurl/hash.c | 315 -- Utilities/cmcurl/hash.h | 61 - Utilities/cmcurl/hostares.c | 307 -- Utilities/cmcurl/hostasyn.c | 174 -- Utilities/cmcurl/hostip.c | 636 ---- Utilities/cmcurl/hostip.h | 271 -- Utilities/cmcurl/hostip4.c | 389 --- Utilities/cmcurl/hostip6.c | 306 -- Utilities/cmcurl/hostsyn.c | 138 - Utilities/cmcurl/hostthre.c | 840 ------ Utilities/cmcurl/http.c | 2422 --------------- Utilities/cmcurl/http.h | 85 - Utilities/cmcurl/http_chunks.c | 360 --- Utilities/cmcurl/http_chunks.h | 104 - Utilities/cmcurl/http_digest.c | 504 ---- Utilities/cmcurl/http_digest.h | 58 - Utilities/cmcurl/http_negotiate.c | 327 -- Utilities/cmcurl/http_negotiate.h | 39 - Utilities/cmcurl/http_ntlm.c | 1111 ------- Utilities/cmcurl/http_ntlm.h | 146 - Utilities/cmcurl/if2ip.c | 134 - Utilities/cmcurl/if2ip.h | 67 - Utilities/cmcurl/include/ca-bundle.h | 1 + Utilities/cmcurl/include/curl/curl.h | 1644 +++++++++++ Utilities/cmcurl/include/curl/curlver.h | 56 + Utilities/cmcurl/include/curl/easy.h | 81 + Utilities/cmcurl/include/curl/mprintf.h | 80 + Utilities/cmcurl/include/curl/multi.h | 327 ++ Utilities/cmcurl/include/curl/stdcheaders.h | 34 + Utilities/cmcurl/include/curl/types.h | 1 + Utilities/cmcurl/inet_ntoa_r.h | 44 - Utilities/cmcurl/inet_ntop.c | 224 -- Utilities/cmcurl/inet_ntop.h | 37 - Utilities/cmcurl/inet_pton.c | 241 -- Utilities/cmcurl/inet_pton.h | 42 - Utilities/cmcurl/krb4.c | 425 --- Utilities/cmcurl/krb4.h | 70 - Utilities/cmcurl/ldap.c | 702 ----- Utilities/cmcurl/ldap.h | 29 - Utilities/cmcurl/lib/amigaos.c | 74 + Utilities/cmcurl/lib/amigaos.h | 58 + Utilities/cmcurl/lib/arpa_telnet.h | 101 + Utilities/cmcurl/lib/base64.c | 366 +++ Utilities/cmcurl/lib/base64.h | 28 + Utilities/cmcurl/lib/connect.c | 905 ++++++ Utilities/cmcurl/lib/connect.h | 46 + Utilities/cmcurl/lib/content_encoding.c | 424 +++ Utilities/cmcurl/lib/content_encoding.h | 41 + Utilities/cmcurl/lib/cookie.c | 1019 +++++++ Utilities/cmcurl/lib/cookie.h | 107 + Utilities/cmcurl/lib/curlx.h | 107 + Utilities/cmcurl/lib/dict.c | 280 ++ Utilities/cmcurl/lib/dict.h | 30 + Utilities/cmcurl/lib/easy.c | 895 ++++++ Utilities/cmcurl/lib/easyif.h | 40 + Utilities/cmcurl/lib/escape.c | 181 ++ Utilities/cmcurl/lib/escape.h | 30 + Utilities/cmcurl/lib/file.c | 407 +++ Utilities/cmcurl/lib/file.h | 31 + Utilities/cmcurl/lib/formdata.c | 1694 +++++++++++ Utilities/cmcurl/lib/formdata.h | 97 + Utilities/cmcurl/lib/ftp.c | 3865 ++++++++++++++++++++++++ Utilities/cmcurl/lib/ftp.h | 43 + Utilities/cmcurl/lib/getenv.c | 69 + Utilities/cmcurl/lib/getinfo.c | 234 ++ Utilities/cmcurl/lib/getinfo.h | 28 + Utilities/cmcurl/lib/gtls.c | 640 ++++ Utilities/cmcurl/lib/gtls.h | 46 + Utilities/cmcurl/lib/hash.c | 315 ++ Utilities/cmcurl/lib/hash.h | 61 + Utilities/cmcurl/lib/hostares.c | 307 ++ Utilities/cmcurl/lib/hostasyn.c | 174 ++ Utilities/cmcurl/lib/hostip.c | 636 ++++ Utilities/cmcurl/lib/hostip.h | 271 ++ Utilities/cmcurl/lib/hostip4.c | 389 +++ Utilities/cmcurl/lib/hostip6.c | 306 ++ Utilities/cmcurl/lib/hostsyn.c | 138 + Utilities/cmcurl/lib/hostthre.c | 840 ++++++ Utilities/cmcurl/lib/http.c | 2422 +++++++++++++++ Utilities/cmcurl/lib/http.h | 85 + Utilities/cmcurl/lib/http_chunks.c | 360 +++ Utilities/cmcurl/lib/http_chunks.h | 104 + Utilities/cmcurl/lib/http_digest.c | 504 ++++ Utilities/cmcurl/lib/http_digest.h | 58 + Utilities/cmcurl/lib/http_negotiate.c | 327 ++ Utilities/cmcurl/lib/http_negotiate.h | 39 + Utilities/cmcurl/lib/http_ntlm.c | 1111 +++++++ Utilities/cmcurl/lib/http_ntlm.h | 146 + Utilities/cmcurl/lib/if2ip.c | 134 + Utilities/cmcurl/lib/if2ip.h | 67 + Utilities/cmcurl/lib/inet_ntoa_r.h | 44 + Utilities/cmcurl/lib/inet_ntop.c | 224 ++ Utilities/cmcurl/lib/inet_ntop.h | 37 + Utilities/cmcurl/lib/inet_pton.c | 241 ++ Utilities/cmcurl/lib/inet_pton.h | 42 + Utilities/cmcurl/lib/krb4.c | 425 +++ Utilities/cmcurl/lib/krb4.h | 70 + Utilities/cmcurl/lib/ldap.c | 702 +++++ Utilities/cmcurl/lib/ldap.h | 29 + Utilities/cmcurl/lib/llist.c | 138 + Utilities/cmcurl/lib/llist.h | 60 + Utilities/cmcurl/lib/md5.c | 352 +++ Utilities/cmcurl/lib/md5.h | 29 + Utilities/cmcurl/lib/memdebug.c | 298 ++ Utilities/cmcurl/lib/memdebug.h | 125 + Utilities/cmcurl/lib/memory.h | 50 + Utilities/cmcurl/lib/mprintf.c | 1218 ++++++++ Utilities/cmcurl/lib/multi.c | 1988 +++++++++++++ Utilities/cmcurl/lib/multiif.h | 46 + Utilities/cmcurl/lib/netrc.c | 247 ++ Utilities/cmcurl/lib/netrc.h | 34 + Utilities/cmcurl/lib/nwlib.c | 300 ++ Utilities/cmcurl/lib/parsedate.c | 425 +++ Utilities/cmcurl/lib/parsedate.h | 28 + Utilities/cmcurl/lib/progress.c | 424 +++ Utilities/cmcurl/lib/progress.h | 70 + Utilities/cmcurl/lib/security.c | 493 ++++ Utilities/cmcurl/lib/select.c | 315 ++ Utilities/cmcurl/lib/select.h | 60 + Utilities/cmcurl/lib/sendf.c | 663 +++++ Utilities/cmcurl/lib/sendf.h | 72 + Utilities/cmcurl/lib/setup.h | 390 +++ Utilities/cmcurl/lib/setup_once.h | 153 + Utilities/cmcurl/lib/share.c | 219 ++ Utilities/cmcurl/lib/share.h | 56 + Utilities/cmcurl/lib/sockaddr.h | 38 + Utilities/cmcurl/lib/socks.c | 592 ++++ Utilities/cmcurl/lib/socks.h | 41 + Utilities/cmcurl/lib/speedcheck.c | 75 + Utilities/cmcurl/lib/speedcheck.h | 34 + Utilities/cmcurl/lib/splay.c | 425 +++ Utilities/cmcurl/lib/splay.h | 54 + Utilities/cmcurl/lib/ssh.c | 979 ++++++ Utilities/cmcurl/lib/ssh.h | 49 + Utilities/cmcurl/lib/sslgen.c | 618 ++++ Utilities/cmcurl/lib/sslgen.h | 84 + Utilities/cmcurl/lib/ssluse.c | 1950 ++++++++++++ Utilities/cmcurl/lib/ssluse.h | 71 + Utilities/cmcurl/lib/strdup.c | 46 + Utilities/cmcurl/lib/strdup.h | 34 + Utilities/cmcurl/lib/strequal.c | 101 + Utilities/cmcurl/lib/strequal.h | 38 + Utilities/cmcurl/lib/strerror.c | 751 +++++ Utilities/cmcurl/lib/strerror.h | 34 + Utilities/cmcurl/lib/strtok.c | 68 + Utilities/cmcurl/lib/strtok.h | 38 + Utilities/cmcurl/lib/strtoofft.c | 165 ++ Utilities/cmcurl/lib/strtoofft.h | 73 + Utilities/cmcurl/lib/telnet.c | 1403 +++++++++ Utilities/cmcurl/lib/telnet.h | 30 + Utilities/cmcurl/lib/tftp.c | 816 +++++ Utilities/cmcurl/lib/tftp.h | 31 + Utilities/cmcurl/lib/timeval.c | 116 + Utilities/cmcurl/lib/timeval.h | 76 + Utilities/cmcurl/lib/transfer.c | 2494 ++++++++++++++++ Utilities/cmcurl/lib/transfer.h | 51 + Utilities/cmcurl/lib/url.c | 4252 +++++++++++++++++++++++++++ Utilities/cmcurl/lib/url.h | 85 + Utilities/cmcurl/lib/urldata.h | 1340 +++++++++ Utilities/cmcurl/lib/version.c | 249 ++ Utilities/cmcurl/llist.c | 138 - Utilities/cmcurl/llist.h | 60 - Utilities/cmcurl/md5.c | 352 --- Utilities/cmcurl/md5.h | 29 - Utilities/cmcurl/memdebug.c | 298 -- Utilities/cmcurl/memdebug.h | 125 - Utilities/cmcurl/memory.h | 50 - Utilities/cmcurl/mprintf.c | 1218 -------- Utilities/cmcurl/multi.c | 1988 ------------- Utilities/cmcurl/multiif.h | 46 - Utilities/cmcurl/netrc.c | 247 -- Utilities/cmcurl/netrc.h | 34 - Utilities/cmcurl/nwlib.c | 300 -- Utilities/cmcurl/parsedate.c | 425 --- Utilities/cmcurl/parsedate.h | 28 - Utilities/cmcurl/progress.c | 424 --- Utilities/cmcurl/progress.h | 70 - Utilities/cmcurl/security.c | 493 ---- Utilities/cmcurl/select.c | 315 -- Utilities/cmcurl/select.h | 60 - Utilities/cmcurl/sendf.c | 663 ----- Utilities/cmcurl/sendf.h | 72 - Utilities/cmcurl/setup.h | 390 --- Utilities/cmcurl/setup_once.h | 153 - Utilities/cmcurl/share.c | 219 -- Utilities/cmcurl/share.h | 56 - Utilities/cmcurl/sockaddr.h | 38 - Utilities/cmcurl/socks.c | 592 ---- Utilities/cmcurl/socks.h | 41 - Utilities/cmcurl/speedcheck.c | 75 - Utilities/cmcurl/speedcheck.h | 34 - Utilities/cmcurl/splay.c | 425 --- Utilities/cmcurl/splay.h | 54 - Utilities/cmcurl/ssh.c | 979 ------ Utilities/cmcurl/ssh.h | 49 - Utilities/cmcurl/sslgen.c | 618 ---- Utilities/cmcurl/sslgen.h | 84 - Utilities/cmcurl/ssluse.c | 1950 ------------ Utilities/cmcurl/ssluse.h | 71 - Utilities/cmcurl/strdup.c | 46 - Utilities/cmcurl/strdup.h | 34 - Utilities/cmcurl/strequal.c | 101 - Utilities/cmcurl/strequal.h | 38 - Utilities/cmcurl/strerror.c | 751 ----- Utilities/cmcurl/strerror.h | 34 - Utilities/cmcurl/strtok.c | 68 - Utilities/cmcurl/strtok.h | 38 - Utilities/cmcurl/strtoofft.c | 165 -- Utilities/cmcurl/strtoofft.h | 73 - Utilities/cmcurl/telnet.c | 1403 --------- Utilities/cmcurl/telnet.h | 30 - Utilities/cmcurl/tftp.c | 816 ----- Utilities/cmcurl/tftp.h | 31 - Utilities/cmcurl/timeval.c | 116 - Utilities/cmcurl/timeval.h | 76 - Utilities/cmcurl/transfer.c | 2494 ---------------- Utilities/cmcurl/transfer.h | 51 - Utilities/cmcurl/url.c | 4252 --------------------------- Utilities/cmcurl/url.h | 85 - Utilities/cmcurl/urldata.h | 1340 --------- Utilities/cmcurl/version.c | 249 -- 260 files changed, 50342 insertions(+), 50342 deletions(-) delete mode 100644 Utilities/cmcurl/amigaos.c delete mode 100644 Utilities/cmcurl/amigaos.h delete mode 100644 Utilities/cmcurl/arpa_telnet.h delete mode 100644 Utilities/cmcurl/base64.c delete mode 100644 Utilities/cmcurl/base64.h delete mode 100644 Utilities/cmcurl/ca-bundle.h delete mode 100644 Utilities/cmcurl/connect.c delete mode 100644 Utilities/cmcurl/connect.h delete mode 100644 Utilities/cmcurl/content_encoding.c delete mode 100644 Utilities/cmcurl/content_encoding.h delete mode 100644 Utilities/cmcurl/cookie.c delete mode 100644 Utilities/cmcurl/cookie.h delete mode 100644 Utilities/cmcurl/curl/curl.h delete mode 100644 Utilities/cmcurl/curl/curlver.h delete mode 100644 Utilities/cmcurl/curl/easy.h delete mode 100644 Utilities/cmcurl/curl/mprintf.h delete mode 100644 Utilities/cmcurl/curl/multi.h delete mode 100644 Utilities/cmcurl/curl/stdcheaders.h delete mode 100644 Utilities/cmcurl/curl/types.h delete mode 100644 Utilities/cmcurl/curlx.h delete mode 100644 Utilities/cmcurl/dict.c delete mode 100644 Utilities/cmcurl/dict.h delete mode 100644 Utilities/cmcurl/easy.c delete mode 100644 Utilities/cmcurl/easyif.h delete mode 100644 Utilities/cmcurl/escape.c delete mode 100644 Utilities/cmcurl/escape.h delete mode 100644 Utilities/cmcurl/file.c delete mode 100644 Utilities/cmcurl/file.h delete mode 100644 Utilities/cmcurl/formdata.c delete mode 100644 Utilities/cmcurl/formdata.h delete mode 100644 Utilities/cmcurl/ftp.c delete mode 100644 Utilities/cmcurl/ftp.h delete mode 100644 Utilities/cmcurl/getenv.c delete mode 100644 Utilities/cmcurl/getinfo.c delete mode 100644 Utilities/cmcurl/getinfo.h delete mode 100644 Utilities/cmcurl/gtls.c delete mode 100644 Utilities/cmcurl/gtls.h delete mode 100644 Utilities/cmcurl/hash.c delete mode 100644 Utilities/cmcurl/hash.h delete mode 100644 Utilities/cmcurl/hostares.c delete mode 100644 Utilities/cmcurl/hostasyn.c delete mode 100644 Utilities/cmcurl/hostip.c delete mode 100644 Utilities/cmcurl/hostip.h delete mode 100644 Utilities/cmcurl/hostip4.c delete mode 100644 Utilities/cmcurl/hostip6.c delete mode 100644 Utilities/cmcurl/hostsyn.c delete mode 100644 Utilities/cmcurl/hostthre.c delete mode 100644 Utilities/cmcurl/http.c delete mode 100644 Utilities/cmcurl/http.h delete mode 100644 Utilities/cmcurl/http_chunks.c delete mode 100644 Utilities/cmcurl/http_chunks.h delete mode 100644 Utilities/cmcurl/http_digest.c delete mode 100644 Utilities/cmcurl/http_digest.h delete mode 100644 Utilities/cmcurl/http_negotiate.c delete mode 100644 Utilities/cmcurl/http_negotiate.h delete mode 100644 Utilities/cmcurl/http_ntlm.c delete mode 100644 Utilities/cmcurl/http_ntlm.h delete mode 100644 Utilities/cmcurl/if2ip.c delete mode 100644 Utilities/cmcurl/if2ip.h create mode 100644 Utilities/cmcurl/include/ca-bundle.h create mode 100644 Utilities/cmcurl/include/curl/curl.h create mode 100644 Utilities/cmcurl/include/curl/curlver.h create mode 100644 Utilities/cmcurl/include/curl/easy.h create mode 100644 Utilities/cmcurl/include/curl/mprintf.h create mode 100644 Utilities/cmcurl/include/curl/multi.h create mode 100644 Utilities/cmcurl/include/curl/stdcheaders.h create mode 100644 Utilities/cmcurl/include/curl/types.h delete mode 100644 Utilities/cmcurl/inet_ntoa_r.h delete mode 100644 Utilities/cmcurl/inet_ntop.c delete mode 100644 Utilities/cmcurl/inet_ntop.h delete mode 100644 Utilities/cmcurl/inet_pton.c delete mode 100644 Utilities/cmcurl/inet_pton.h delete mode 100644 Utilities/cmcurl/krb4.c delete mode 100644 Utilities/cmcurl/krb4.h delete mode 100644 Utilities/cmcurl/ldap.c delete mode 100644 Utilities/cmcurl/ldap.h create mode 100644 Utilities/cmcurl/lib/amigaos.c create mode 100644 Utilities/cmcurl/lib/amigaos.h create mode 100644 Utilities/cmcurl/lib/arpa_telnet.h create mode 100644 Utilities/cmcurl/lib/base64.c create mode 100644 Utilities/cmcurl/lib/base64.h create mode 100644 Utilities/cmcurl/lib/connect.c create mode 100644 Utilities/cmcurl/lib/connect.h create mode 100644 Utilities/cmcurl/lib/content_encoding.c create mode 100644 Utilities/cmcurl/lib/content_encoding.h create mode 100644 Utilities/cmcurl/lib/cookie.c create mode 100644 Utilities/cmcurl/lib/cookie.h create mode 100644 Utilities/cmcurl/lib/curlx.h create mode 100644 Utilities/cmcurl/lib/dict.c create mode 100644 Utilities/cmcurl/lib/dict.h create mode 100644 Utilities/cmcurl/lib/easy.c create mode 100644 Utilities/cmcurl/lib/easyif.h create mode 100644 Utilities/cmcurl/lib/escape.c create mode 100644 Utilities/cmcurl/lib/escape.h create mode 100644 Utilities/cmcurl/lib/file.c create mode 100644 Utilities/cmcurl/lib/file.h create mode 100644 Utilities/cmcurl/lib/formdata.c create mode 100644 Utilities/cmcurl/lib/formdata.h create mode 100644 Utilities/cmcurl/lib/ftp.c create mode 100644 Utilities/cmcurl/lib/ftp.h create mode 100644 Utilities/cmcurl/lib/getenv.c create mode 100644 Utilities/cmcurl/lib/getinfo.c create mode 100644 Utilities/cmcurl/lib/getinfo.h create mode 100644 Utilities/cmcurl/lib/gtls.c create mode 100644 Utilities/cmcurl/lib/gtls.h create mode 100644 Utilities/cmcurl/lib/hash.c create mode 100644 Utilities/cmcurl/lib/hash.h create mode 100644 Utilities/cmcurl/lib/hostares.c create mode 100644 Utilities/cmcurl/lib/hostasyn.c create mode 100644 Utilities/cmcurl/lib/hostip.c create mode 100644 Utilities/cmcurl/lib/hostip.h create mode 100644 Utilities/cmcurl/lib/hostip4.c create mode 100644 Utilities/cmcurl/lib/hostip6.c create mode 100644 Utilities/cmcurl/lib/hostsyn.c create mode 100644 Utilities/cmcurl/lib/hostthre.c create mode 100644 Utilities/cmcurl/lib/http.c create mode 100644 Utilities/cmcurl/lib/http.h create mode 100644 Utilities/cmcurl/lib/http_chunks.c create mode 100644 Utilities/cmcurl/lib/http_chunks.h create mode 100644 Utilities/cmcurl/lib/http_digest.c create mode 100644 Utilities/cmcurl/lib/http_digest.h create mode 100644 Utilities/cmcurl/lib/http_negotiate.c create mode 100644 Utilities/cmcurl/lib/http_negotiate.h create mode 100644 Utilities/cmcurl/lib/http_ntlm.c create mode 100644 Utilities/cmcurl/lib/http_ntlm.h create mode 100644 Utilities/cmcurl/lib/if2ip.c create mode 100644 Utilities/cmcurl/lib/if2ip.h create mode 100644 Utilities/cmcurl/lib/inet_ntoa_r.h create mode 100644 Utilities/cmcurl/lib/inet_ntop.c create mode 100644 Utilities/cmcurl/lib/inet_ntop.h create mode 100644 Utilities/cmcurl/lib/inet_pton.c create mode 100644 Utilities/cmcurl/lib/inet_pton.h create mode 100644 Utilities/cmcurl/lib/krb4.c create mode 100644 Utilities/cmcurl/lib/krb4.h create mode 100644 Utilities/cmcurl/lib/ldap.c create mode 100644 Utilities/cmcurl/lib/ldap.h create mode 100644 Utilities/cmcurl/lib/llist.c create mode 100644 Utilities/cmcurl/lib/llist.h create mode 100644 Utilities/cmcurl/lib/md5.c create mode 100644 Utilities/cmcurl/lib/md5.h create mode 100644 Utilities/cmcurl/lib/memdebug.c create mode 100644 Utilities/cmcurl/lib/memdebug.h create mode 100644 Utilities/cmcurl/lib/memory.h create mode 100644 Utilities/cmcurl/lib/mprintf.c create mode 100644 Utilities/cmcurl/lib/multi.c create mode 100644 Utilities/cmcurl/lib/multiif.h create mode 100644 Utilities/cmcurl/lib/netrc.c create mode 100644 Utilities/cmcurl/lib/netrc.h create mode 100644 Utilities/cmcurl/lib/nwlib.c create mode 100644 Utilities/cmcurl/lib/parsedate.c create mode 100644 Utilities/cmcurl/lib/parsedate.h create mode 100644 Utilities/cmcurl/lib/progress.c create mode 100644 Utilities/cmcurl/lib/progress.h create mode 100644 Utilities/cmcurl/lib/security.c create mode 100644 Utilities/cmcurl/lib/select.c create mode 100644 Utilities/cmcurl/lib/select.h create mode 100644 Utilities/cmcurl/lib/sendf.c create mode 100644 Utilities/cmcurl/lib/sendf.h create mode 100644 Utilities/cmcurl/lib/setup.h create mode 100644 Utilities/cmcurl/lib/setup_once.h create mode 100644 Utilities/cmcurl/lib/share.c create mode 100644 Utilities/cmcurl/lib/share.h create mode 100644 Utilities/cmcurl/lib/sockaddr.h create mode 100644 Utilities/cmcurl/lib/socks.c create mode 100644 Utilities/cmcurl/lib/socks.h create mode 100644 Utilities/cmcurl/lib/speedcheck.c create mode 100644 Utilities/cmcurl/lib/speedcheck.h create mode 100644 Utilities/cmcurl/lib/splay.c create mode 100644 Utilities/cmcurl/lib/splay.h create mode 100644 Utilities/cmcurl/lib/ssh.c create mode 100644 Utilities/cmcurl/lib/ssh.h create mode 100644 Utilities/cmcurl/lib/sslgen.c create mode 100644 Utilities/cmcurl/lib/sslgen.h create mode 100644 Utilities/cmcurl/lib/ssluse.c create mode 100644 Utilities/cmcurl/lib/ssluse.h create mode 100644 Utilities/cmcurl/lib/strdup.c create mode 100644 Utilities/cmcurl/lib/strdup.h create mode 100644 Utilities/cmcurl/lib/strequal.c create mode 100644 Utilities/cmcurl/lib/strequal.h create mode 100644 Utilities/cmcurl/lib/strerror.c create mode 100644 Utilities/cmcurl/lib/strerror.h create mode 100644 Utilities/cmcurl/lib/strtok.c create mode 100644 Utilities/cmcurl/lib/strtok.h create mode 100644 Utilities/cmcurl/lib/strtoofft.c create mode 100644 Utilities/cmcurl/lib/strtoofft.h create mode 100644 Utilities/cmcurl/lib/telnet.c create mode 100644 Utilities/cmcurl/lib/telnet.h create mode 100644 Utilities/cmcurl/lib/tftp.c create mode 100644 Utilities/cmcurl/lib/tftp.h create mode 100644 Utilities/cmcurl/lib/timeval.c create mode 100644 Utilities/cmcurl/lib/timeval.h create mode 100644 Utilities/cmcurl/lib/transfer.c create mode 100644 Utilities/cmcurl/lib/transfer.h create mode 100644 Utilities/cmcurl/lib/url.c create mode 100644 Utilities/cmcurl/lib/url.h create mode 100644 Utilities/cmcurl/lib/urldata.h create mode 100644 Utilities/cmcurl/lib/version.c delete mode 100644 Utilities/cmcurl/llist.c delete mode 100644 Utilities/cmcurl/llist.h delete mode 100644 Utilities/cmcurl/md5.c delete mode 100644 Utilities/cmcurl/md5.h delete mode 100644 Utilities/cmcurl/memdebug.c delete mode 100644 Utilities/cmcurl/memdebug.h delete mode 100644 Utilities/cmcurl/memory.h delete mode 100644 Utilities/cmcurl/mprintf.c delete mode 100644 Utilities/cmcurl/multi.c delete mode 100644 Utilities/cmcurl/multiif.h delete mode 100644 Utilities/cmcurl/netrc.c delete mode 100644 Utilities/cmcurl/netrc.h delete mode 100644 Utilities/cmcurl/nwlib.c delete mode 100644 Utilities/cmcurl/parsedate.c delete mode 100644 Utilities/cmcurl/parsedate.h delete mode 100644 Utilities/cmcurl/progress.c delete mode 100644 Utilities/cmcurl/progress.h delete mode 100644 Utilities/cmcurl/security.c delete mode 100644 Utilities/cmcurl/select.c delete mode 100644 Utilities/cmcurl/select.h delete mode 100644 Utilities/cmcurl/sendf.c delete mode 100644 Utilities/cmcurl/sendf.h delete mode 100644 Utilities/cmcurl/setup.h delete mode 100644 Utilities/cmcurl/setup_once.h delete mode 100644 Utilities/cmcurl/share.c delete mode 100644 Utilities/cmcurl/share.h delete mode 100644 Utilities/cmcurl/sockaddr.h delete mode 100644 Utilities/cmcurl/socks.c delete mode 100644 Utilities/cmcurl/socks.h delete mode 100644 Utilities/cmcurl/speedcheck.c delete mode 100644 Utilities/cmcurl/speedcheck.h delete mode 100644 Utilities/cmcurl/splay.c delete mode 100644 Utilities/cmcurl/splay.h delete mode 100644 Utilities/cmcurl/ssh.c delete mode 100644 Utilities/cmcurl/ssh.h delete mode 100644 Utilities/cmcurl/sslgen.c delete mode 100644 Utilities/cmcurl/sslgen.h delete mode 100644 Utilities/cmcurl/ssluse.c delete mode 100644 Utilities/cmcurl/ssluse.h delete mode 100644 Utilities/cmcurl/strdup.c delete mode 100644 Utilities/cmcurl/strdup.h delete mode 100644 Utilities/cmcurl/strequal.c delete mode 100644 Utilities/cmcurl/strequal.h delete mode 100644 Utilities/cmcurl/strerror.c delete mode 100644 Utilities/cmcurl/strerror.h delete mode 100644 Utilities/cmcurl/strtok.c delete mode 100644 Utilities/cmcurl/strtok.h delete mode 100644 Utilities/cmcurl/strtoofft.c delete mode 100644 Utilities/cmcurl/strtoofft.h delete mode 100644 Utilities/cmcurl/telnet.c delete mode 100644 Utilities/cmcurl/telnet.h delete mode 100644 Utilities/cmcurl/tftp.c delete mode 100644 Utilities/cmcurl/tftp.h delete mode 100644 Utilities/cmcurl/timeval.c delete mode 100644 Utilities/cmcurl/timeval.h delete mode 100644 Utilities/cmcurl/transfer.c delete mode 100644 Utilities/cmcurl/transfer.h delete mode 100644 Utilities/cmcurl/url.c delete mode 100644 Utilities/cmcurl/url.h delete mode 100644 Utilities/cmcurl/urldata.h delete mode 100644 Utilities/cmcurl/version.c diff --git a/Utilities/cm_curl.h b/Utilities/cm_curl.h index 43944a3..a3b049b 100644 --- a/Utilities/cm_curl.h +++ b/Utilities/cm_curl.h @@ -17,7 +17,7 @@ #ifdef CMAKE_USE_SYSTEM_CURL # include #else -# include +# include #endif #endif diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 97fd2ff..a48de2d 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -34,75 +34,75 @@ INCLUDE (CheckSymbolExists) INCLUDE (CheckTypeSize) SET(libCurl_SRCS - # amigaos.c - does not build on AmigaOS - base64.c - connect.c - content_encoding.c - cookie.c - dict.c - easy.c - escape.c - file.c - formdata.c - ftp.c - getenv.c - getinfo.c - gtls.c - hash.c - hostares.c - hostasyn.c - hostip4.c - hostip6.c - hostip.c - hostsyn.c - hostthre.c - http.c - http_chunks.c - http_digest.c - http_negotiate.c - http_ntlm.c - if2ip.c - inet_ntop.c - inet_pton.c - krb4.c - ldap.c - llist.c - md5.c -# memdebug.c -not used - mprintf.c - multi.c - netrc.c - # nwlib.c - Not used - parsedate.c - progress.c - security.c - select.c - sendf.c - share.c - socks.c - speedcheck.c - splay.c - ssh.c - sslgen.c - ssluse.c - strdup.c - strequal.c - strerror.c - # strtok.c - specify later - # strtoofft.c - specify later - telnet.c - tftp.c - timeval.c - transfer.c - url.c - version.c + # lib/amigaos.c - does not build on AmigaOS + lib/base64.c + lib/connect.c + lib/content_encoding.c + lib/cookie.c + lib/dict.c + lib/easy.c + lib/escape.c + lib/file.c + lib/formdata.c + lib/ftp.c + lib/getenv.c + lib/getinfo.c + lib/gtls.c + lib/hash.c + lib/hostares.c + lib/hostasyn.c + lib/hostip4.c + lib/hostip6.c + lib/hostip.c + lib/hostsyn.c + lib/hostthre.c + lib/http.c + lib/http_chunks.c + lib/http_digest.c + lib/http_negotiate.c + lib/http_ntlm.c + lib/if2ip.c + lib/inet_ntop.c + lib/inet_pton.c + lib/krb4.c + lib/ldap.c + lib/llist.c + lib/md5.c +# lib/memdebug.c -not used + lib/mprintf.c + lib/multi.c + lib/netrc.c + # lib/nwlib.c - Not used + lib/parsedate.c + lib/progress.c + lib/security.c + lib/select.c + lib/sendf.c + lib/share.c + lib/socks.c + lib/speedcheck.c + lib/splay.c + lib/ssh.c + lib/sslgen.c + lib/ssluse.c + lib/strdup.c + lib/strequal.c + lib/strerror.c + # lib/strtok.c - specify later + # lib/strtoofft.c - specify later + lib/telnet.c + lib/tftp.c + lib/timeval.c + lib/transfer.c + lib/url.c + lib/version.c ) SET(CURL_DISABLE_LDAP 1) IF(NOT CURL_DISABLE_LDAP) SET(libCurl_SRCS ${libCurl_SRCS} - ldap.c + lib/ldap.c ) ENDIF(NOT CURL_DISABLE_LDAP) @@ -110,8 +110,8 @@ ENDIF(NOT CURL_DISABLE_LDAP) #OPTION(CURL_KRB4 "Use Kerberos 4" OFF) IF(CURL_KRB4) SET(libCurl_SRCS ${libCurl_SRCS} - krb4.c - security.c + lib/krb4.c + lib/security.c ) ENDIF(CURL_KRB4) @@ -119,7 +119,7 @@ ENDIF(CURL_KRB4) MARK_AS_ADVANCED(CURL_MALLOC_DEBUG) IF(CURL_MALLOC_DEBUG) SET(libCurl_SRCS ${libCurl_SRCS} - memdebug.c + lib/memdebug.c ) ENDIF(CURL_MALLOC_DEBUG) @@ -169,7 +169,7 @@ ENDIF(NOT CURL_SPECIAL_LIBZ) # Include the local directories before any others so that we do not end up # including system curl's include directory first by mistake. -INCLUDE_DIRECTORIES(${LIBCURL_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${LIBCURL_SOURCE_DIR}/include) INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR}) OPTION(CMAKE_USE_OPENSSL "Use OpenSSL code with curl." OFF) @@ -472,14 +472,14 @@ CHECK_SYMBOL_EXISTS(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) # only build compat strtok if we need to IF (NOT HAVE_STRTOK_R) SET(libCurl_SRCS ${libCurl_SRCS} - strtok.c + lib/strtok.c ) ENDIF (NOT HAVE_STRTOK_R) # only build compat strtoofft if we need to IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) SET(libCurl_SRCS ${libCurl_SRCS} - strtoofft.c + lib/strtoofft.c ) ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) diff --git a/Utilities/cmcurl/amigaos.c b/Utilities/cmcurl/amigaos.c deleted file mode 100644 index 7106f8d..0000000 --- a/Utilities/cmcurl/amigaos.c +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "amigaos.h" -#include - -struct Library *SocketBase = NULL; -extern int errno, h_errno; - -#ifdef __libnix__ -#include -void __request(const char *msg); -#else -# define __request( msg ) Printf( msg "\n\a") -#endif - -void amiga_cleanup() -{ - if(SocketBase) { - CloseLibrary(SocketBase); - SocketBase = NULL; - } -} - -BOOL amiga_init() -{ - if(!SocketBase) - SocketBase = OpenLibrary("bsdsocket.library", 4); - - if(!SocketBase) { - __request("No TCP/IP Stack running!"); - return FALSE; - } - - if(SocketBaseTags( - SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, -// SBTM_SETVAL(SBTC_HERRNOLONGPTR), (ULONG) &h_errno, - SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL", - TAG_DONE)) { - - __request("SocketBaseTags ERROR"); - return FALSE; - } - -#ifndef __libnix__ - atexit(amiga_cleanup); -#endif - - return TRUE; -} - -#ifdef __libnix__ -ADD2EXIT(amiga_cleanup,-50); -#endif diff --git a/Utilities/cmcurl/amigaos.h b/Utilities/cmcurl/amigaos.h deleted file mode 100644 index e5786d4..0000000 --- a/Utilities/cmcurl/amigaos.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifndef LIBCURL_AMIGAOS_H -#define LIBCURL_AMIGAOS_H - -#ifndef __ixemul__ - -#include -#include - -#include -#include - -#include - -#include "config-amigaos.h" - -#ifndef select -# define select(args...) WaitSelect( args, NULL) -#endif -#ifndef inet_ntoa -# define inet_ntoa(x) Inet_NtoA( x ## .s_addr) -#endif -#ifndef ioctl -# define ioctl(a,b,c,d) IoctlSocket( (LONG)a, (ULONG)b, (char*)c) -#endif -#define _AMIGASF 1 - -extern void amiga_cleanup(); -extern BOOL amiga_init(); - -#else /* __ixemul__ */ - -#warning compiling with ixemul... - -#endif /* __ixemul__ */ -#endif /* LIBCURL_AMIGAOS_H */ diff --git a/Utilities/cmcurl/arpa_telnet.h b/Utilities/cmcurl/arpa_telnet.h deleted file mode 100644 index e6a04dc..0000000 --- a/Utilities/cmcurl/arpa_telnet.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef __ARPA_TELNET_H -#define __ARPA_TELNET_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_TELNET -/* - * Telnet option defines. Add more here if in need. - */ -#define CURL_TELOPT_BINARY 0 /* binary 8bit data */ -#define CURL_TELOPT_SGA 3 /* Supress Go Ahead */ -#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ -#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ -#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ - -#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */ -#define CURL_NEW_ENV_VAR 0 -#define CURL_NEW_ENV_VALUE 1 - -/* - * The telnet options represented as strings - */ -static const char * const telnetoptions[]= -{ - "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", - "NAME", "STATUS", "TIMING MARK", "RCTE", - "NAOL", "NAOP", "NAOCRD", "NAOHTS", - "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", - "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", - "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", - "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", - "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS", - "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC", - "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON" -}; - -#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON - -#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM) -#define CURL_TELOPT(x) telnetoptions[x] - -#define CURL_NTELOPTS 40 - -/* - * First some defines - */ -#define CURL_xEOF 236 /* End Of File */ -#define CURL_SE 240 /* Sub negotiation End */ -#define CURL_NOP 241 /* No OPeration */ -#define CURL_DM 242 /* Data Mark */ -#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 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 */ - -/* - * Then those numbers represented as strings: - */ -static const char * const telnetcmds[]= -{ - "EOF", "SUSP", "ABORT", "EOR", "SE", - "NOP", "DMARK", "BRK", "IP", "AO", - "AYT", "EC", "EL", "GA", "SB", - "WILL", "WONT", "DO", "DONT", "IAC" -}; - -#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */ -#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */ - -#define CURL_TELQUAL_IS 0 -#define CURL_TELQUAL_SEND 1 -#define CURL_TELQUAL_INFO 2 -#define CURL_TELQUAL_NAME 3 - -#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \ - ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) ) -#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM] -#endif -#endif diff --git a/Utilities/cmcurl/base64.c b/Utilities/cmcurl/base64.c deleted file mode 100644 index aa03f83..0000000 --- a/Utilities/cmcurl/base64.c +++ /dev/null @@ -1,366 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* Base64 encoding/decoding - * - * Test harnesses down the bottom - compile with -DTEST_ENCODE for - * a program that will read in raw data from stdin and write out - * a base64-encoded version to stdout, and the length returned by the - * encoding function to stderr. Compile with -DTEST_DECODE for a program that - * will go the other way. - * - * This code will break if int is smaller than 32 bits - */ - -#include "setup.h" - -#include -#include - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "urldata.h" /* for the SessionHandle definition */ -#include "easyif.h" /* for Curl_convert_... prototypes */ -#include "base64.h" -#include "memory.h" - -/* include memdebug.h last */ -#include "memdebug.h" - -/* ---- Base64 Encoding/Decoding Table --- */ -static const char table64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static void decodeQuantum(unsigned char *dest, const char *src) -{ - unsigned int x = 0; - int i; - char *found; - - for(i = 0; i < 4; i++) { - if((found = strchr(table64, src[i]))) - x = (x << 6) + (unsigned int)(found - table64); - else if(src[i] == '=') - x = (x << 6); - } - - dest[2] = (unsigned char)(x & 255); - x >>= 8; - dest[1] = (unsigned char)(x & 255); - x >>= 8; - dest[0] = (unsigned char)(x & 255); -} - -/* - * Curl_base64_decode() - * - * Given a base64 string at src, decode it and return an allocated memory in - * the *outptr. Returns the length of the decoded data. - */ -size_t Curl_base64_decode(const char *src, unsigned char **outptr) -{ - int length = 0; - int equalsTerm = 0; - int i; - int numQuantums; - unsigned char lastQuantum[3]; - size_t rawlen=0; - unsigned char *newstr; - - *outptr = NULL; - - while((src[length] != '=') && src[length]) - length++; - /* A maximum of two = padding characters is allowed */ - if(src[length] == '=') { - equalsTerm++; - if(src[length+equalsTerm] == '=') - equalsTerm++; - } - numQuantums = (length + equalsTerm) / 4; - - /* Don't allocate a buffer if the decoded length is 0 */ - if (numQuantums <= 0) - return 0; - - rawlen = (numQuantums * 3) - equalsTerm; - - /* The buffer must be large enough to make room for the last quantum - (which may be partially thrown out) and the zero terminator. */ - newstr = malloc(rawlen+4); - if(!newstr) - return 0; - - *outptr = newstr; - - /* Decode all but the last quantum (which may not decode to a - multiple of 3 bytes) */ - for(i = 0; i < numQuantums - 1; i++) { - decodeQuantum((unsigned char *)newstr, src); - newstr += 3; src += 4; - } - - /* This final decode may actually read slightly past the end of the buffer - if the input string is missing pad bytes. This will almost always be - harmless. */ - decodeQuantum(lastQuantum, src); - for(i = 0; i < 3 - equalsTerm; i++) - newstr[i] = lastQuantum[i]; - - newstr[i] = 0; /* zero terminate */ - return rawlen; -} - -/* - * Curl_base64_encode() - * - * Returns the length of the newly created base64 string. The third argument - * is a pointer to an allocated area holding the base64 data. If something - * went wrong, -1 is returned. - * - */ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inp, size_t insize, char **outptr) -{ - unsigned char ibuf[3]; - unsigned char obuf[4]; - int i; - int inputparts; - char *output; - char *base64data; -#ifdef CURL_DOES_CONVERSIONS - char *convbuf; -#endif - - char *indata = (char *)inp; - - *outptr = NULL; /* set to NULL in case of failure before we reach the end */ - - if(0 == insize) - insize = strlen(indata); - - base64data = output = (char*)malloc(insize*4/3+4); - if(NULL == output) - return 0; - -#ifdef CURL_DOES_CONVERSIONS - /* - * The base64 data needs to be created using the network encoding - * not the host encoding. And we can't change the actual input - * so we copy it to a buffer, translate it, and use that instead. - */ - if(data) { - convbuf = (char*)malloc(insize); - if(!convbuf) { - return 0; - } - memcpy(convbuf, indata, insize); - if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) { - free(convbuf); - return 0; - } - indata = convbuf; /* switch to the converted buffer */ - } -#else - (void)data; -#endif - - while(insize > 0) { - for (i = inputparts = 0; i < 3; i++) { - if(insize > 0) { - inputparts++; - ibuf[i] = *indata; - indata++; - insize--; - } - else - ibuf[i] = 0; - } - - obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); - obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ - ((ibuf[1] & 0xF0) >> 4)); - obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ - ((ibuf[2] & 0xC0) >> 6)); - obuf[3] = (unsigned char) (ibuf[2] & 0x3F); - - switch(inputparts) { - case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); - break; - case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); - break; - default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]] ); - break; - } - output += 4; - } - *output=0; - *outptr = base64data; /* make it return the actual data memory */ - -#ifdef CURL_DOES_CONVERSIONS - if(data) - free(convbuf); -#endif - return strlen(base64data); /* return the length of the new data */ -} -/* ---- End of Base64 Encoding ---- */ - -/************* TEST HARNESS STUFF ****************/ - - -#ifdef TEST_ENCODE -/* encoding test harness. Read in standard input and write out the length - * returned by Curl_base64_encode, followed by the base64'd data itself - */ -#include - -#define TEST_NEED_SUCK -void *suck(int *); - -int main(int argc, char **argv, char **envp) -{ - char *base64; - size_t base64Len; - unsigned char *data; - int dataLen; - struct SessionHandle *handle = NULL; - -#ifdef CURL_DOES_CONVERSIONS - /* get a Curl handle so Curl_base64_encode can translate properly */ - handle = curl_easy_init(); - if(handle == NULL) { - fprintf(stderr, "Error: curl_easy_init failed\n"); - return 0; - } -#endif - data = (unsigned char *)suck(&dataLen); - base64Len = Curl_base64_encode(handle, data, dataLen, &base64); - - fprintf(stderr, "%d\n", base64Len); - fprintf(stdout, "%s\n", base64); - - free(base64); free(data); -#ifdef CURL_DOES_CONVERSIONS - curl_easy_cleanup(handle); -#endif - return 0; -} -#endif - -#ifdef TEST_DECODE -/* decoding test harness. Read in a base64 string from stdin and write out the - * length returned by Curl_base64_decode, followed by the decoded data itself - * - * gcc -DTEST_DECODE base64.c -o base64 mprintf.o memdebug.o - */ -#include - -#define TEST_NEED_SUCK -void *suck(int *); - -int main(int argc, char **argv, char **envp) -{ - char *base64; - int base64Len; - unsigned char *data; - int dataLen; - int i, j; -#ifdef CURL_DOES_CONVERSIONS - /* get a Curl handle so main can translate properly */ - struct SessionHandle *handle = curl_easy_init(); - if(handle == NULL) { - fprintf(stderr, "Error: curl_easy_init failed\n"); - return 0; - } -#endif - - base64 = (char *)suck(&base64Len); - dataLen = Curl_base64_decode(base64, &data); - - fprintf(stderr, "%d\n", dataLen); - - for(i=0; i < dataLen; i+=0x10) { - printf("0x%02x: ", i); - for(j=0; j < 0x10; j++) - if((j+i) < dataLen) - printf("%02x ", data[i+j]); - else - printf(" "); - - printf(" | "); - - for(j=0; j < 0x10; j++) - if((j+i) < dataLen) { -#ifdef CURL_DOES_CONVERSIONS - if(CURLE_OK != - Curl_convert_from_network(handle, &data[i+j], (size_t)1)) - data[i+j] = '.'; -#endif /* CURL_DOES_CONVERSIONS */ - printf("%c", ISGRAPH(data[i+j])?data[i+j]:'.'); - } else - break; - puts(""); - } - -#ifdef CURL_DOES_CONVERSIONS - curl_easy_cleanup(handle); -#endif - free(base64); free(data); - return 0; -} -#endif - -#ifdef TEST_NEED_SUCK -/* this function 'sucks' in as much as possible from stdin */ -void *suck(int *lenptr) -{ - int cursize = 8192; - unsigned char *buf = NULL; - int lastread; - int len = 0; - - do { - cursize *= 2; - buf = (unsigned char *)realloc(buf, cursize); - memset(buf + len, 0, cursize - len); - lastread = fread(buf + len, 1, cursize - len, stdin); - len += lastread; - } while(!feof(stdin)); - - lenptr[0] = len; - return (void *)buf; -} -#endif diff --git a/Utilities/cmcurl/base64.h b/Utilities/cmcurl/base64.h deleted file mode 100644 index 59742bc..0000000 --- a/Utilities/cmcurl/base64.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __BASE64_H -#define __BASE64_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *input, size_t size, char **str); -size_t Curl_base64_decode(const char *source, unsigned char **outptr); -#endif diff --git a/Utilities/cmcurl/ca-bundle.h b/Utilities/cmcurl/ca-bundle.h deleted file mode 100644 index 12390bc..0000000 --- a/Utilities/cmcurl/ca-bundle.h +++ /dev/null @@ -1 +0,0 @@ -/* ca bundle path set in here*/ diff --git a/Utilities/cmcurl/connect.c b/Utilities/cmcurl/connect.c deleted file mode 100644 index 2b38972..0000000 --- a/Utilities/cmcurl/connect.c +++ /dev/null @@ -1,905 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef WIN32 -/* headers for non-win32 */ -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include /* may need it */ -#endif -#ifdef HAVE_NETINET_TCP_H -#include /* for TCP_NODELAY */ -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototype, without it, this crashes - on macos 68K */ -#endif -#if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__)) -#include -#endif -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif -#ifdef VMS -#include -#include -#endif - -#endif -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#ifdef USE_WINSOCK -#define EINPROGRESS WSAEINPROGRESS -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EISCONN WSAEISCONN -#define ENOTSOCK WSAENOTSOCK -#define ECONNREFUSED WSAECONNREFUSED -#endif - -#include "urldata.h" -#include "sendf.h" -#include "if2ip.h" -#include "strerror.h" -#include "connect.h" -#include "memory.h" -#include "select.h" -#include "url.h" /* for Curl_safefree() */ -#include "multiif.h" -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "inet_ntop.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -static bool verifyconnect(curl_socket_t sockfd, int *error); - -static curl_socket_t -singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, /* start connecting to this */ - long timeout_ms, - bool *connected); - -/* - * Curl_sockerrno() returns the *socket-related* errno (or equivalent) on this - * platform to hide platform specific for the function that calls this. - */ -int Curl_sockerrno(void) -{ -#ifdef USE_WINSOCK - return (int)WSAGetLastError(); -#else - return errno; -#endif -} - -/* - * Curl_nonblock() set the given socket to either blocking or non-blocking - * mode based on the 'nonblock' boolean argument. This function is highly - * portable. - */ -int Curl_nonblock(curl_socket_t sockfd, /* operate on this */ - int nonblock /* TRUE or FALSE */) -{ -#undef SETBLOCK -#define SETBLOCK 0 -#ifdef HAVE_O_NONBLOCK - /* most recent unix versions */ - int flags; - - flags = fcntl(sockfd, F_GETFL, 0); - if (TRUE == nonblock) - return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); - else - return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); -#undef SETBLOCK -#define SETBLOCK 1 -#endif - -#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) - /* older unix versions */ - int flags; - - flags = nonblock; - return ioctl(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 2 -#endif - -#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) - /* Windows? */ - unsigned long flags; - flags = nonblock; - - return ioctlsocket(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 3 -#endif - -#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) - /* presumably for Amiga */ - return IoctlSocket(sockfd, FIONBIO, (long)nonblock); -#undef SETBLOCK -#define SETBLOCK 4 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) - /* BeOS */ - long b = nonblock ? 1 : 0; - return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); -#undef SETBLOCK -#define SETBLOCK 5 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING - return 0; /* returns success */ -#undef SETBLOCK -#define SETBLOCK 6 -#endif - -#if (SETBLOCK == 0) -#error "no non-blocking method was found/used/set" -#endif -} - -/* - * waitconnect() waits for a TCP connect on the given socket for the specified - * number if milliseconds. It returns: - * 0 fine connect - * -1 select() error - * 1 select() timeout - * 2 select() returned with an error condition fd_set - */ - -#define WAITCONN_CONNECTED 0 -#define WAITCONN_SELECT_ERROR -1 -#define WAITCONN_TIMEOUT 1 -#define WAITCONN_FDSET_ERROR 2 - -static -int waitconnect(curl_socket_t sockfd, /* socket */ - long timeout_msec) -{ - int rc; -#ifdef mpeix - /* Call this function once now, and ignore the results. We do this to - "clear" the error state on the socket so that we can later read it - reliably. This is reported necessary on the MPE/iX operating system. */ - (void)verifyconnect(sockfd, NULL); -#endif - - /* now select() until we get connect or timeout */ - rc = Curl_select(CURL_SOCKET_BAD, sockfd, (int)timeout_msec); - if(-1 == rc) - /* error, no connect here, try next */ - return WAITCONN_SELECT_ERROR; - - else if(0 == rc) - /* timeout, no connect today */ - return WAITCONN_TIMEOUT; - - if(rc & CSELECT_ERR) - /* error condition caught */ - return WAITCONN_FDSET_ERROR; - - /* we have a connect! */ - return WAITCONN_CONNECTED; -} - -static CURLcode bindlocal(struct connectdata *conn, - curl_socket_t sockfd) -{ - struct SessionHandle *data = conn->data; - struct sockaddr_in me; - struct sockaddr *sock = NULL; /* bind to this address */ - socklen_t socksize; /* size of the data sock points to */ - unsigned short port = data->set.localport; /* use this port number, 0 for - "random" */ - /* how many port numbers to try to bind to, increasing one at a time */ - int portnum = data->set.localportrange; - - /************************************************************* - * Select device to bind socket to - *************************************************************/ - if (data->set.device && (strlen(data->set.device)<255) ) { - struct Curl_dns_entry *h=NULL; - char myhost[256] = ""; - in_addr_t in; - int rc; - bool was_iface = FALSE; - - /* First check if the given name is an IP address */ - in=inet_addr(data->set.device); - - if((in == CURL_INADDR_NONE) && - Curl_if2ip(data->set.device, myhost, sizeof(myhost))) { - /* - * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer - */ - rc = Curl_resolv(conn, myhost, 0, &h); - if(rc == CURLRESOLV_PENDING) - (void)Curl_wait_for_resolv(conn, &h); - - if(h) { - was_iface = TRUE; - Curl_resolv_unlock(data, h); - } - } - - if(!was_iface) { - /* - * This was not an interface, resolve the name as a host name - * or IP number - */ - rc = Curl_resolv(conn, data->set.device, 0, &h); - if(rc == CURLRESOLV_PENDING) - (void)Curl_wait_for_resolv(conn, &h); - - if(h) { - if(in == CURL_INADDR_NONE) - /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ - Curl_inet_ntop(h->addr->ai_addr->sa_family, - &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr, - myhost, sizeof myhost); - else - /* we know data->set.device is shorter than the myhost array */ - strcpy(myhost, data->set.device); - Curl_resolv_unlock(data, h); - } - } - - if(! *myhost) { - /* need to fix this - h=Curl_gethost(data, - getmyhost(*myhost,sizeof(myhost)), - hostent_buf, - sizeof(hostent_buf)); - */ - failf(data, "Couldn't bind to '%s'", data->set.device); - return CURLE_HTTP_PORT_FAILED; - } - - infof(data, "Bind local address to %s\n", myhost); - -#ifdef SO_BINDTODEVICE - /* I am not sure any other OSs than Linux that provide this feature, and - * at the least I cannot test. --Ben - * - * This feature allows one to tightly bind the local socket to a - * particular interface. This will force even requests to other local - * interfaces to go out the external interface. - * - */ - if (was_iface) { - /* Only bind to the interface when specified as interface, not just as a - * hostname or ip address. - */ - if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - data->set.device, strlen(data->set.device)+1) != 0) { - /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n", - sockfd, data->set.device, Curl_strerror(Curl_sockerrno())); */ - infof(data, "SO_BINDTODEVICE %s failed\n", - data->set.device); - /* This is typically "errno 1, error: Operation not permitted" if - you're not running as root or another suitable privileged user */ - } - } -#endif - - in=inet_addr(myhost); - if (CURL_INADDR_NONE == in) { - failf(data,"couldn't find my own IP address (%s)", myhost); - return CURLE_HTTP_PORT_FAILED; - } /* end of inet_addr */ - - if ( h ) { - Curl_addrinfo *addr = h->addr; - sock = addr->ai_addr; - socksize = addr->ai_addrlen; - } - else - return CURLE_HTTP_PORT_FAILED; - - } - else if(port) { - /* if a local port number is requested but no local IP, extract the - address from the socket */ - memset(&me, 0, sizeof(struct sockaddr)); - me.sin_family = AF_INET; - me.sin_addr.s_addr = INADDR_ANY; - - sock = (struct sockaddr *)&me; - socksize = sizeof(struct sockaddr); - - } - else - /* no local kind of binding was requested */ - return CURLE_OK; - - do { - - /* Set port number to bind to, 0 makes the system pick one */ - if(sock->sa_family == AF_INET) - ((struct sockaddr_in *)sock)->sin_port = htons(port); -#ifdef ENABLE_IPV6 - else - ((struct sockaddr_in6 *)sock)->sin6_port = htons(port); -#endif - - if( bind(sockfd, sock, socksize) >= 0) { - /* we succeeded to bind */ - struct Curl_sockaddr_storage add; - socklen_t size; - - size = sizeof(add); - if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { - failf(data, "getsockname() failed"); - return CURLE_HTTP_PORT_FAILED; - } - /* We re-use/clobber the port variable here below */ - if(((struct sockaddr *)&add)->sa_family == AF_INET) - port = ntohs(((struct sockaddr_in *)&add)->sin_port); -#ifdef ENABLE_IPV6 - else - port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port); -#endif - infof(data, "Local port: %d\n", port); - return CURLE_OK; - } - if(--portnum > 0) { - infof(data, "Bind to local port %d failed, trying next\n", port); - port++; /* try next port */ - } - else - break; - } while(1); - - data->state.os_errno = Curl_sockerrno(); - failf(data, "bind failure: %s", - Curl_strerror(conn, data->state.os_errno)); - return CURLE_HTTP_PORT_FAILED; - -} - -/* - * verifyconnect() returns TRUE if the connect really has happened. - */ -static bool verifyconnect(curl_socket_t sockfd, int *error) -{ - bool rc = TRUE; -#ifdef SO_ERROR - int err = 0; - socklen_t errSize = sizeof(err); - -#ifdef WIN32 - /* - * In October 2003 we effectively nullified this function on Windows due to - * problems with it using all CPU in multi-threaded cases. - * - * In May 2004, we bring it back to offer more info back on connect failures. - * Gisle Vanem could reproduce the former problems with this function, but - * could avoid them by adding this SleepEx() call below: - * - * "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. - * - * Someone got to verify this on Win-NT 4.0, 2000." - */ - -#ifdef _WIN32_WCE - Sleep(0); -#else - SleepEx(0, FALSE); -#endif - -#endif - - if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR, - (void *)&err, &errSize)) - err = Curl_sockerrno(); - -#ifdef _WIN32_WCE - /* Always returns this error, bug in CE? */ - if(WSAENOPROTOOPT==err) - err=0; -#endif - - if ((0 == err) || (EISCONN == err)) - /* we are connected, awesome! */ - rc = TRUE; - else - /* This wasn't a successful connect */ - rc = FALSE; - if (error) - *error = err; -#else - (void)sockfd; - if (error) - *error = Curl_sockerrno(); -#endif - return rc; -} - -CURLcode Curl_store_ip_addr(struct connectdata *conn) -{ - char addrbuf[256]; - Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf)); - - /* save the string */ - Curl_safefree(conn->ip_addr_str); - conn->ip_addr_str = strdup(addrbuf); - if(!conn->ip_addr_str) - return CURLE_OUT_OF_MEMORY; /* FAIL */ - -#ifdef PF_INET6 - if(conn->ip_addr->ai_family == PF_INET6) - conn->bits.ipv6 = TRUE; -#endif - - return CURLE_OK; -} - -/* Used within the multi interface. Try next IP address, return TRUE if no - more address exists */ -static bool trynextip(struct connectdata *conn, - int sockindex, - bool *connected) -{ - curl_socket_t sockfd; - Curl_addrinfo *ai; - - /* first close the failed socket */ - sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - *connected = FALSE; - - if(sockindex != FIRSTSOCKET) - return TRUE; /* no next */ - - /* try the next address */ - ai = conn->ip_addr->ai_next; - - while (ai) { - sockfd = singleipconnect(conn, ai, 0L, connected); - if(sockfd != CURL_SOCKET_BAD) { - /* store the new socket descriptor */ - conn->sock[sockindex] = sockfd; - conn->ip_addr = ai; - - Curl_store_ip_addr(conn); - return FALSE; - } - ai = ai->ai_next; - } - return TRUE; -} - -/* - * Curl_is_connected() is used from the multi interface to check if the - * firstsocket has connected. - */ - -CURLcode Curl_is_connected(struct connectdata *conn, - int sockindex, - bool *connected) -{ - int rc; - struct SessionHandle *data = conn->data; - CURLcode code = CURLE_OK; - curl_socket_t sockfd = conn->sock[sockindex]; - long allow = DEFAULT_CONNECT_TIMEOUT; - long allow_total = 0; - long has_passed; - - curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); - - *connected = FALSE; /* a very negative world view is best */ - - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - - /* subtract the most strict timeout of the ones */ - if(data->set.timeout && data->set.connecttimeout) { - if (data->set.timeout < data->set.connecttimeout) - allow_total = allow = data->set.timeout*1000; - else - allow = data->set.connecttimeout*1000; - } - else if(data->set.timeout) { - allow_total = allow = data->set.timeout*1000; - } - else if(data->set.connecttimeout) { - allow = data->set.connecttimeout*1000; - } - - if(has_passed > allow ) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out after %ld ms", has_passed); - return CURLE_OPERATION_TIMEOUTED; - } - if(conn->bits.tcpconnect) { - /* we are connected already! */ - Curl_expire(data, allow_total); - *connected = TRUE; - return CURLE_OK; - } - - Curl_expire(data, allow); - - /* check for connect without timeout as we want to return immediately */ - rc = waitconnect(sockfd, 0); - - if(WAITCONN_CONNECTED == rc) { - int error; - if (verifyconnect(sockfd, &error)) { - /* we are connected, awesome! */ - *connected = TRUE; - return CURLE_OK; - } - /* nope, not connected for real */ - data->state.os_errno = error; - infof(data, "Connection failed\n"); - if(trynextip(conn, sockindex, connected)) { - code = CURLE_COULDNT_CONNECT; - } - } - else if(WAITCONN_TIMEOUT != rc) { - int error = 0; - - /* nope, not connected */ - if (WAITCONN_FDSET_ERROR == rc) { - (void)verifyconnect(sockfd, &error); - data->state.os_errno = error; - infof(data, "%s\n",Curl_strerror(conn,error)); - } - else - infof(data, "Connection failed\n"); - - if(trynextip(conn, sockindex, connected)) { - error = Curl_sockerrno(); - data->state.os_errno = error; - failf(data, "Failed connect to %s:%d; %s", - conn->host.name, conn->port, Curl_strerror(conn,error)); - code = CURLE_COULDNT_CONNECT; - } - } - /* - * If the connection failed here, we should attempt to connect to the "next - * address" for the given host. - */ - - return code; -} - -static void tcpnodelay(struct connectdata *conn, - curl_socket_t sockfd) -{ -#ifdef TCP_NODELAY - struct SessionHandle *data= conn->data; - socklen_t onoff = (socklen_t) data->set.tcp_nodelay; - int proto = IPPROTO_TCP; - -#ifdef HAVE_GETPROTOBYNAME - struct protoent *pe = getprotobyname("tcp"); - if (pe) - proto = pe->p_proto; -#endif - - if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff, - sizeof(onoff)) < 0) - infof(data, "Could not set TCP_NODELAY: %s\n", - Curl_strerror(conn, Curl_sockerrno())); - else - infof(data,"TCP_NODELAY set\n"); -#else - (void)conn; - (void)sockfd; -#endif -} - -#ifdef SO_NOSIGPIPE -/* 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? */ -static void nosigpipe(struct connectdata *conn, - curl_socket_t sockfd) -{ - struct SessionHandle *data= conn->data; - int onoff = 1; - if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, - sizeof(onoff)) < 0) - infof(data, "Could not set SO_NOSIGPIPE: %s\n", - Curl_strerror(conn, Curl_sockerrno())); -} -#else -#define nosigpipe(x,y) -#endif - -/* singleipconnect() connects to the given IP only, and it may return without - having connected if used from the multi interface. */ -static curl_socket_t -singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, - long timeout_ms, - bool *connected) -{ - char addr_buf[128]; - int rc; - int error; - bool isconnected; - struct SessionHandle *data = conn->data; - curl_socket_t sockfd; - CURLcode res; - - sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol); - if (sockfd == CURL_SOCKET_BAD) - return CURL_SOCKET_BAD; - - *connected = FALSE; /* default is not connected */ - - Curl_printable_address(ai, addr_buf, sizeof(addr_buf)); - infof(data, " Trying %s... ", addr_buf); - - if(data->set.tcp_nodelay) - tcpnodelay(conn, sockfd); - - nosigpipe(conn, sockfd); - - if(data->set.fsockopt) { - /* activate callback for setting socket options */ - error = data->set.fsockopt(data->set.sockopt_client, - sockfd, - CURLSOCKTYPE_IPCXN); - if (error) { - sclose(sockfd); /* close the socket and bail out */ - return CURL_SOCKET_BAD; - } - } - - /* possibly bind the local end to an IP, interface or port */ - res = bindlocal(conn, sockfd); - if(res) { - sclose(sockfd); /* close socket and bail out */ - return CURL_SOCKET_BAD; - } - - /* set socket non-blocking */ - Curl_nonblock(sockfd, TRUE); - - /* Connect TCP sockets, bind UDP */ - if(conn->socktype == SOCK_STREAM) - rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); - else - rc = 0; - - if(-1 == rc) { - error = Curl_sockerrno(); - - switch (error) { - case EINPROGRESS: - case EWOULDBLOCK: -#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK - /* On some platforms EAGAIN and EWOULDBLOCK are the - * same value, and on others they are different, hence - * the odd #if - */ - case EAGAIN: -#endif - rc = waitconnect(sockfd, timeout_ms); - break; - default: - /* unknown error, fallthrough and try another address! */ - failf(data, "Failed to connect to %s: %s", - addr_buf, Curl_strerror(conn,error)); - data->state.os_errno = error; - break; - } - } - - /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from - connect(). We can be sure of this since connect() cannot return 1. */ - if((WAITCONN_TIMEOUT == rc) && - (data->state.used_interface == Curl_if_multi)) { - /* Timeout when running the multi interface */ - return sockfd; - } - - isconnected = verifyconnect(sockfd, &error); - - if(!rc && isconnected) { - /* we are connected, awesome! */ - *connected = TRUE; /* this is a true connect */ - infof(data, "connected\n"); - return sockfd; - } - else if(WAITCONN_TIMEOUT == rc) - infof(data, "Timeout\n"); - else { - data->state.os_errno = error; - infof(data, "%s\n", Curl_strerror(conn, error)); - } - - /* connect failed or timed out */ - sclose(sockfd); - - return CURL_SOCKET_BAD; -} - -/* - * TCP connect to the given host with timeout, proxy or remote doesn't matter. - * There might be more than one IP address to try out. Fill in the passed - * pointer with the connected socket. - */ - -CURLcode Curl_connecthost(struct connectdata *conn, /* context */ - const struct Curl_dns_entry *remotehost, /* use this one */ - curl_socket_t *sockconn, /* the connected socket */ - Curl_addrinfo **addr, /* the one we used */ - bool *connected) /* really connected? */ -{ - struct SessionHandle *data = conn->data; - curl_socket_t sockfd = CURL_SOCKET_BAD; - int aliasindex; - int num_addr; - Curl_addrinfo *ai; - Curl_addrinfo *curr_addr; - - struct timeval after; - struct timeval before = Curl_tvnow(); - - /************************************************************* - * Figure out what maximum time we have left - *************************************************************/ - long timeout_ms= DEFAULT_CONNECT_TIMEOUT; - long timeout_per_addr; - - *connected = FALSE; /* default to not connected */ - - if(data->set.timeout || data->set.connecttimeout) { - long has_passed; - - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif - - /* get the most strict timeout of the ones converted to milliseconds */ - if(data->set.timeout && data->set.connecttimeout) { - if (data->set.timeout < data->set.connecttimeout) - timeout_ms = data->set.timeout*1000; - else - timeout_ms = data->set.connecttimeout*1000; - } - else if(data->set.timeout) - timeout_ms = data->set.timeout*1000; - else - timeout_ms = data->set.connecttimeout*1000; - - /* subtract the passed time */ - timeout_ms -= has_passed; - - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEOUTED; - } - } - Curl_expire(data, timeout_ms); - - /* Max time for each address */ - num_addr = Curl_num_addresses(remotehost->addr); - timeout_per_addr = timeout_ms / num_addr; - - ai = remotehost->addr; - - /* Below is the loop that attempts to connect to all IP-addresses we - * know for the given host. One by one until one IP succeeds. - */ - - if(data->state.used_interface == Curl_if_multi) - /* don't hang when doing multi */ - timeout_per_addr = 0; - - /* - * Connecting with a Curl_addrinfo chain - */ - for (curr_addr = ai, aliasindex=0; curr_addr; - curr_addr = curr_addr->ai_next, aliasindex++) { - - /* start connecting to the IP curr_addr points to */ - sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected); - - if(sockfd != CURL_SOCKET_BAD) - break; - - /* get a new timeout for next attempt */ - after = Curl_tvnow(); - timeout_ms -= Curl_tvdiff(after, before); - if(timeout_ms < 0) { - failf(data, "connect() timed out!"); - return CURLE_OPERATION_TIMEOUTED; - } - before = after; - } /* end of connect-to-each-address loop */ - - if (sockfd == CURL_SOCKET_BAD) { - /* no good connect was made */ - *sockconn = CURL_SOCKET_BAD; - failf(data, "couldn't connect to host"); - return CURLE_COULDNT_CONNECT; - } - - /* leave the socket in non-blocking mode */ - - /* store the address we use */ - if(addr) - *addr = curr_addr; - - /* allow NULL-pointers to get passed in */ - if(sockconn) - *sockconn = sockfd; /* the socket descriptor we've connected */ - - data->info.numconnects++; /* to track the number of connections made */ - - return CURLE_OK; -} diff --git a/Utilities/cmcurl/connect.h b/Utilities/cmcurl/connect.h deleted file mode 100644 index 599572b..0000000 --- a/Utilities/cmcurl/connect.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __CONNECT_H -#define __CONNECT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -int Curl_nonblock(curl_socket_t sockfd, /* operate on this */ - int nonblock /* TRUE or FALSE */); - -CURLcode Curl_is_connected(struct connectdata *conn, - int sockindex, - bool *connected); - -CURLcode Curl_connecthost(struct connectdata *conn, - const struct Curl_dns_entry *host, /* connect to this */ - curl_socket_t *sockconn, /* not set if error */ - Curl_addrinfo **addr, /* the one we used */ - bool *connected /* truly connected? */ - ); - -int Curl_sockerrno(void); - -CURLcode Curl_store_ip_addr(struct connectdata *conn); - -#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ - -#endif diff --git a/Utilities/cmcurl/content_encoding.c b/Utilities/cmcurl/content_encoding.c deleted file mode 100644 index 97f8341..0000000 --- a/Utilities/cmcurl/content_encoding.c +++ /dev/null @@ -1,424 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifdef HAVE_LIBZ - -#include -#include - -#include "urldata.h" -#include -#include "sendf.h" -#include "content_encoding.h" -#include "memory.h" - -#include "memdebug.h" - -/* Comment this out if zlib is always going to be at least ver. 1.2.0.4 - (doing so will reduce code size slightly). */ -#define OLD_ZLIB_SUPPORT 1 - -#define DSIZ 0x10000 /* buffer size for decompressed data */ - -#define GZIP_MAGIC_0 0x1f -#define GZIP_MAGIC_1 0x8b - -/* gzip flag byte */ -#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 file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -enum zlibState { - ZLIB_UNINIT, /* uninitialized */ - ZLIB_INIT, /* initialized */ - ZLIB_GZIP_HEADER, /* reading gzip header */ - ZLIB_GZIP_INFLATING, /* inflating gzip stream */ - ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ -}; - -static CURLcode -process_zlib_error(struct connectdata *conn, z_stream *z) -{ - struct SessionHandle *data = conn->data; - if (z->msg) - failf (data, "Error while processing content unencoding: %s", - z->msg); - else - failf (data, "Error while processing content unencoding: " - "Unknown failure within decompression software."); - - return CURLE_BAD_CONTENT_ENCODING; -} - -static CURLcode -exit_zlib(z_stream *z, bool *zlib_init, CURLcode result) -{ - inflateEnd(z); - *zlib_init = ZLIB_UNINIT; - return result; -} - -static CURLcode -inflate_stream(struct connectdata *conn, - struct Curl_transfer_keeper *k) -{ - int allow_restart = 1; - z_stream *z = &k->z; /* zlib state structure */ - uInt nread = z->avail_in; - Bytef *orig_in = z->next_in; - int status; /* zlib status */ - CURLcode result = CURLE_OK; /* Curl_client_write status */ - char *decomp; /* Put the decompressed data here. */ - - /* Dynamically allocate a buffer for decompression because it's uncommonly - large to hold on the stack */ - decomp = (char*)malloc(DSIZ); - if (decomp == NULL) { - return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); - } - - /* because the buffer size is fixed, iteratively decompress and transfer to - the client via client_write. */ - for (;;) { - /* (re)set buffer for decompressed output for every iteration */ - z->next_out = (Bytef *)decomp; - z->avail_out = DSIZ; - - status = inflate(z, Z_SYNC_FLUSH); - if (status == Z_OK || status == Z_STREAM_END) { - allow_restart = 0; - if(DSIZ - z->avail_out) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp, - DSIZ - z->avail_out); - /* if !CURLE_OK, clean up, return */ - if (result) { - free(decomp); - return exit_zlib(z, &k->zlib_init, result); - } - } - - /* Done? clean up, return */ - if (status == Z_STREAM_END) { - free(decomp); - if (inflateEnd(z) == Z_OK) - return exit_zlib(z, &k->zlib_init, result); - else - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - - /* Done with these bytes, exit */ - if (status == Z_OK && z->avail_in == 0) { - free(decomp); - return result; - } - } - else if (allow_restart && status == Z_DATA_ERROR) { - /* some servers seem to not generate zlib headers, so this is an attempt - to fix and continue anyway */ - - inflateReset(z); - if (inflateInit2(z, -MAX_WBITS) != Z_OK) { - return process_zlib_error(conn, z); - } - z->next_in = orig_in; - z->avail_in = nread; - allow_restart = 0; - continue; - } - else { /* Error; exit loop, handle below */ - free(decomp); - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - } - /* Will never get here */ -} - -CURLcode -Curl_unencode_deflate_write(struct connectdata *conn, - struct Curl_transfer_keeper *k, - ssize_t nread) -{ - z_stream *z = &k->z; /* zlib state structure */ - - /* Initialize zlib? */ - if (k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; - if (inflateInit(z) != Z_OK) - return process_zlib_error(conn, z); - k->zlib_init = ZLIB_INIT; - } - - /* Set the compressed input when this function is called */ - z->next_in = (Bytef *)k->str; - z->avail_in = (uInt)nread; - - /* Now uncompress the data */ - return inflate_stream(conn, k); -} - -#ifdef OLD_ZLIB_SUPPORT -/* Skip over the gzip header */ -static enum { - GZIP_OK, - GZIP_BAD, - GZIP_UNDERFLOW -} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen) -{ - int method, flags; - const ssize_t totallen = len; - - /* The shortest header is 10 bytes */ - if (len < 10) - return GZIP_UNDERFLOW; - - if ((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1)) - return GZIP_BAD; - - method = data[2]; - flags = data[3]; - - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - /* Can't handle this compression method or unknown flag */ - return GZIP_BAD; - } - - /* Skip over time, xflags, OS code and all previous bytes */ - len -= 10; - data += 10; - - if (flags & EXTRA_FIELD) { - ssize_t extra_len; - - if (len < 2) - return GZIP_UNDERFLOW; - - extra_len = (data[1] << 8) | data[0]; - - if (len < (extra_len+2)) - return GZIP_UNDERFLOW; - - len -= (extra_len + 2); - data += (extra_len + 2); - } - - if (flags & ORIG_NAME) { - /* Skip over NUL-terminated file name */ - while (len && *data) { - --len; - ++data; - } - if (!len || *data) - return GZIP_UNDERFLOW; - - /* Skip over the NUL */ - --len; - ++data; - } - - if (flags & COMMENT) { - /* Skip over NUL-terminated comment */ - while (len && *data) { - --len; - ++data; - } - if (!len || *data) - return GZIP_UNDERFLOW; - - /* Skip over the NUL */ - --len; - ++data; - } - - if (flags & HEAD_CRC) { - if (len < 2) - return GZIP_UNDERFLOW; - - len -= 2; - data += 2; - } - - *headerlen = totallen - len; - return GZIP_OK; -} -#endif - -CURLcode -Curl_unencode_gzip_write(struct connectdata *conn, - struct Curl_transfer_keeper *k, - ssize_t nread) -{ - z_stream *z = &k->z; /* zlib state structure */ - - /* Initialize zlib? */ - if (k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; - - if (strcmp(zlibVersion(), "1.2.0.4") >= 0) { - /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ - if (inflateInit2(z, MAX_WBITS+32) != Z_OK) { - return process_zlib_error(conn, z); - } - k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ - - } else { - /* we must parse the gzip header ourselves */ - if (inflateInit2(z, -MAX_WBITS) != Z_OK) { - return process_zlib_error(conn, z); - } - k->zlib_init = ZLIB_INIT; /* Initial call state */ - } - } - - if (k->zlib_init == ZLIB_INIT_GZIP) { - /* Let zlib handle the gzip decompression entirely */ - z->next_in = (Bytef *)k->str; - z->avail_in = (uInt)nread; - /* Now uncompress the data */ - return inflate_stream(conn, k); - } - -#ifndef OLD_ZLIB_SUPPORT - /* Support for old zlib versions is compiled away and we are running with - an old version, so return an error. */ - return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND); - -#else - /* 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 - * can handle the gzip header themselves. - */ - - switch (k->zlib_init) { - /* Skip over gzip header? */ - case ZLIB_INIT: - { - /* Initial call state */ - ssize_t hlen; - - switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) { - case GZIP_OK: - z->next_in = (Bytef *)k->str + hlen; - z->avail_in = (uInt)(nread - hlen); - k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ - break; - - case GZIP_UNDERFLOW: - /* 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's unlikely - * that circumstances will be right for this code path to be followed in - * 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)nread; - z->next_in = malloc(z->avail_in); - if (z->next_in == NULL) { - return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); - } - memcpy(z->next_in, k->str, z->avail_in); - k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */ - /* We don't have any data to inflate yet */ - return CURLE_OK; - - case GZIP_BAD: - default: - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - - } - break; - - case ZLIB_GZIP_HEADER: - { - /* Need more gzip header data state */ - ssize_t hlen; - unsigned char *oldblock = z->next_in; - - z->avail_in += nread; - z->next_in = realloc(z->next_in, z->avail_in); - if (z->next_in == NULL) { - free(oldblock); - return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); - } - /* Append the new block of data to the previous one */ - memcpy(z->next_in + z->avail_in - nread, k->str, nread); - - switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) { - case GZIP_OK: - /* This is the zlib stream data */ - free(z->next_in); - /* Don't point into the malloced block since we just freed it */ - z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in; - z->avail_in = (uInt)(z->avail_in - hlen); - k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ - break; - - case GZIP_UNDERFLOW: - /* We still don't have any data to inflate! */ - return CURLE_OK; - - case GZIP_BAD: - default: - free(z->next_in); - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); - } - - } - break; - - case ZLIB_GZIP_INFLATING: - default: - /* Inflating stream state */ - z->next_in = (Bytef *)k->str; - z->avail_in = (uInt)nread; - break; - } - - if (z->avail_in == 0) { - /* We don't have any data to inflate; wait until next time */ - return CURLE_OK; - } - - /* We've parsed the header, now uncompress the data */ - return inflate_stream(conn, k); -#endif -} -#endif /* HAVE_LIBZ */ diff --git a/Utilities/cmcurl/content_encoding.h b/Utilities/cmcurl/content_encoding.h deleted file mode 100644 index b31669b..0000000 --- a/Utilities/cmcurl/content_encoding.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#include "setup.h" - -/* - * Comma-separated list all supported Content-Encodings ('identity' is implied) - */ -#ifdef HAVE_LIBZ -#define ALL_CONTENT_ENCODINGS "deflate, gzip" -#else -#define ALL_CONTENT_ENCODINGS "identity" -#endif - -CURLcode Curl_unencode_deflate_write(struct connectdata *conn, - struct Curl_transfer_keeper *k, - ssize_t nread); - -CURLcode -Curl_unencode_gzip_write(struct connectdata *conn, - struct Curl_transfer_keeper *k, - ssize_t nread); diff --git a/Utilities/cmcurl/cookie.c b/Utilities/cmcurl/cookie.c deleted file mode 100644 index d8ea241..0000000 --- a/Utilities/cmcurl/cookie.c +++ /dev/null @@ -1,1019 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/*** - - -RECEIVING COOKIE INFORMATION -============================ - -struct CookieInfo *cookie_init(char *file); - - Inits a cookie struct to store data in a local file. This is always - called before any cookies are set. - -int cookies_set(struct CookieInfo *cookie, char *cookie_line); - - The 'cookie_line' parameter is a full "Set-cookie:" line as - received from a server. - - The function need to replace previously stored lines that this new - line superceeds. - - It may remove lines that are expired. - - It should return an indication of success/error. - - -SENDING COOKIE INFORMATION -========================== - -struct Cookies *cookie_getlist(struct CookieInfo *cookie, - char *host, char *path, bool secure); - - For a given host and path, return a linked list of cookies that - the client 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 haven't expired. - - -Example set of cookies: - - Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure - Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/ftgw; secure - Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; - domain=.fidelity.com; path=/; secure - Set-cookie: - Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday, - 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure -****/ - - -#include "setup.h" - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - -#include -#include - -#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */ -#include - -#include "urldata.h" -#include "cookie.h" -#include "strequal.h" -#include "strtok.h" -#include "sendf.h" -#include "memory.h" -#include "share.h" -#include "strtoofft.h" - -/* The last #include file should be: */ -#ifdef CURLDEBUG -#include "memdebug.h" -#endif - -#define my_isspace(x) ((x == ' ') || (x == '\t')) - -static void freecookie(struct Cookie *co) -{ - if(co->expirestr) - free(co->expirestr); - if(co->domain) - free(co->domain); - if(co->path) - free(co->path); - if(co->name) - free(co->name); - if(co->value) - free(co->value); - if(co->maxage) - free(co->maxage); - if(co->version) - free(co->version); - - free(co); -} - -static bool tailmatch(const char *little, const char *bigone) -{ - size_t littlelen = strlen(little); - size_t biglen = strlen(bigone); - - if(littlelen > biglen) - return FALSE; - - return (bool)strequal(little, bigone+biglen-littlelen); -} - -/* - * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). - */ -void Curl_cookie_loadfiles(struct SessionHandle *data) -{ - struct curl_slist *list = data->change.cookielist; - if(list) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - while(list) { - data->cookies = Curl_cookie_init(data, - list->data, - data->cookies, - data->set.cookiesession); - list = list->next; - } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - curl_slist_free_all(data->change.cookielist); /* clean up list */ - data->change.cookielist = NULL; /* don't do this again! */ - } -} - -/**************************************************************************** - * - * Curl_cookie_add() - * - * Add a single cookie line to the cookie keeping object. - * - ***************************************************************************/ - -struct Cookie * -Curl_cookie_add(struct SessionHandle *data, - /* The 'data' pointer here may be NULL at times, and thus - must only be used very carefully for things that can deal - with data being NULL. Such as infof() and similar */ - - struct CookieInfo *c, - bool httpheader, /* TRUE if HTTP header-style line */ - char *lineptr, /* first character of the line */ - char *domain, /* default domain */ - char *path) /* full path used when this cookie is set, - used to get default path for the cookie - unless set */ -{ - struct Cookie *clist; - char *what; - char name[MAX_NAME]; - char *ptr; - char *semiptr; - struct Cookie *co; - struct Cookie *lastc=NULL; - time_t now = time(NULL); - bool replace_old = FALSE; - bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ - - /* First, alloc and init a new struct for it */ - co = (struct Cookie *)calloc(sizeof(struct Cookie), 1); - if(!co) - return NULL; /* bail out if we're this low on memory */ - - if(httpheader) { - /* This line was read off a HTTP-header */ - char *sep; - - what = malloc(MAX_COOKIE_LINE); - if(!what) { - free(co); - return NULL; - } - - semiptr=strchr(lineptr, ';'); /* first, find a semicolon */ - - while(*lineptr && my_isspace(*lineptr)) - lineptr++; - - ptr = lineptr; - do { - /* we have a = pair or a 'secure' word here */ - sep = strchr(ptr, '='); - if(sep && (!semiptr || (semiptr>sep)) ) { - /* - * There is a = sign and if there was a semicolon too, which make sure - * that the semicolon comes _after_ the equal sign. - */ - - name[0]=what[0]=0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%" - MAX_COOKIE_LINE_TXT "[^;\r\n]", - name, what)) { - /* this is a = pair */ - - char *whatptr; - - /* Strip off trailing whitespace from the 'what' */ - size_t len=strlen(what); - while(len && my_isspace(what[len-1])) { - what[len-1]=0; - len--; - } - - /* Skip leading whitespace from the 'what' */ - whatptr=what; - while(my_isspace(*whatptr)) { - whatptr++; - } - - if(strequal("path", name)) { - co->path=strdup(whatptr); - if(!co->path) { - badcookie = TRUE; /* out of memory bad */ - break; - } - } - else if(strequal("domain", name)) { - /* note that this name may or may not have a preceeding dot, but - we don't care about that, we treat the names the same anyway */ - - const char *domptr=whatptr; - int dotcount=1; - - /* Count the dots, we need to make sure that there are enough - of them. */ - - if('.' == whatptr[0]) - /* don't count the initial dot, assume it */ - domptr++; - - do { - domptr = strchr(domptr, '.'); - if(domptr) { - domptr++; - dotcount++; - } - } while(domptr); - - /* The original Netscape cookie spec defined that this domain name - MUST have three dots (or two if one of the seven holy TLDs), - but it seems that these kinds of cookies are in use "out there" - so we cannot be that strict. I've therefore lowered the check - to not allow less than two dots. */ - - if(dotcount < 2) { - /* Received and skipped a cookie with a domain using too few - dots. */ - badcookie=TRUE; /* mark this as a bad cookie */ - infof(data, "skipped cookie with illegal dotcount domain: %s\n", - whatptr); - } - else { - /* Now, we make sure that our host is within the given domain, - or the given domain is not valid and thus cannot be set. */ - - if('.' == whatptr[0]) - whatptr++; /* ignore preceeding dot */ - - if(!domain || tailmatch(whatptr, domain)) { - const char *tailptr=whatptr; - if(tailptr[0] == '.') - tailptr++; - co->domain=strdup(tailptr); /* don't prefix w/dots - internally */ - if(!co->domain) { - badcookie = TRUE; - break; - } - co->tailmatch=TRUE; /* we always do that if the domain name was - given */ - } - else { - /* we did not get a tailmatch and then the attempted set domain - is not a domain to which the current host belongs. Mark as - bad. */ - badcookie=TRUE; - infof(data, "skipped cookie with bad tailmatch domain: %s\n", - whatptr); - } - } - } - else if(strequal("version", name)) { - co->version=strdup(whatptr); - if(!co->version) { - badcookie = TRUE; - break; - } - } - else if(strequal("max-age", name)) { - /* 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 - cookie should be discarded immediately. - - */ - co->maxage = strdup(whatptr); - if(!co->maxage) { - badcookie = TRUE; - break; - } - co->expires = - atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now; - } - else if(strequal("expires", name)) { - co->expirestr=strdup(whatptr); - if(!co->expirestr) { - badcookie = TRUE; - break; - } - co->expires = curl_getdate(what, &now); - } - else if(!co->name) { - co->name = strdup(name); - co->value = strdup(whatptr); - if(!co->name || !co->value) { - badcookie = TRUE; - break; - } - } - /* - else this is the second (or more) name we don't know - about! */ - } - else { - /* this is an "illegal" = pair */ - } - } - else { - if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]", - what)) { - if(strequal("secure", what)) - co->secure = TRUE; - /* else, - unsupported keyword without assign! */ - - } - } - if(!semiptr || !*semiptr) { - /* we already know there are no more cookies */ - semiptr = NULL; - continue; - } - - ptr=semiptr+1; - while(ptr && *ptr && my_isspace(*ptr)) - ptr++; - semiptr=strchr(ptr, ';'); /* now, find the next semicolon */ - - if(!semiptr && *ptr) - /* There are no more semicolons, but there's a final name=value pair - coming up */ - semiptr=strchr(ptr, '\0'); - } while(semiptr); - - if(!badcookie && !co->domain) { - if(domain) { - /* no domain was given in the header line, set the default */ - co->domain=strdup(domain); - if(!co->domain) - badcookie = TRUE; - } - } - - if(!badcookie && !co->path && path) { - /* no path was given in the header line, set the default */ - char *endslash = strrchr(path, '/'); - if(endslash) { - size_t pathlen = endslash-path+1; /* include the ending slash */ - co->path=malloc(pathlen+1); /* one extra for the zero byte */ - if(co->path) { - memcpy(co->path, path, pathlen); - co->path[pathlen]=0; /* zero terminate */ - } - else - badcookie = TRUE; - } - } - - free(what); - - if(badcookie || !co->name) { - /* we didn't get a cookie name or a bad one, - this is an illegal line, bail out */ - freecookie(co); - return NULL; - } - - } - else { - /* This line is NOT a HTTP header style line, we do offer support for - reading the odd netscape cookies-file format here */ - char *firstptr; - char *tok_buf; - int fields; - - if(lineptr[0]=='#') { - /* don't even try the comments */ - free(co); - return NULL; - } - /* strip off the possible end-of-line characters */ - ptr=strchr(lineptr, '\r'); - if(ptr) - *ptr=0; /* clear it */ - ptr=strchr(lineptr, '\n'); - if(ptr) - *ptr=0; /* clear it */ - - firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ - - /* Here's a quick check to eliminate normal HTTP-headers from this */ - if(!firstptr || strchr(firstptr, ':')) { - free(co); - return NULL; - } - - /* Now loop through the fields and init the struct we already have - allocated */ - for(ptr=firstptr, fields=0; ptr && !badcookie; - ptr=strtok_r(NULL, "\t", &tok_buf), fields++) { - switch(fields) { - case 0: - if(ptr[0]=='.') /* skip preceeding dots */ - ptr++; - co->domain = strdup(ptr); - if(!co->domain) - badcookie = TRUE; - break; - case 1: - /* This field got its explanation on the 23rd of May 2001 by - Andrés García: - - flag: A TRUE/FALSE value indicating if all machines within a given - domain can access the variable. This value is set automatically by - the browser, depending on the value you set for the domain. - - As far as I can see, it is set to true when the cookie says - .domain.com and to false when the domain is complete www.domain.com - */ - co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */ - break; - case 2: - /* It turns out, that sometimes the file format allows the path - field to remain not filled in, we try to detect this and work - around it! Andrés García made us aware of this... */ - if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { - /* only if the path doesn't look like a boolean option! */ - co->path = strdup(ptr); - if(!co->path) - badcookie = TRUE; - break; - } - /* this doesn't look like a path, make one up! */ - co->path = strdup("/"); - if(!co->path) - badcookie = TRUE; - fields++; /* add a field and fall down to secure */ - /* FALLTHROUGH */ - case 3: - co->secure = (bool)strequal(ptr, "TRUE"); - break; - case 4: - co->expires = curlx_strtoofft(ptr, NULL, 10); - break; - case 5: - co->name = strdup(ptr); - if(!co->name) - badcookie = TRUE; - break; - case 6: - co->value = strdup(ptr); - if(!co->value) - badcookie = TRUE; - break; - } - } - if(6 == fields) { - /* we got a cookie with blank contents, fix it */ - co->value = strdup(""); - if(!co->value) - badcookie = TRUE; - else - fields++; - } - - if(!badcookie && (7 != fields)) - /* we did not find the sufficient number of fields */ - badcookie = TRUE; - - if(badcookie) { - freecookie(co); - return NULL; - } - - } - - if(!c->running && /* read from a file */ - c->newsession && /* clean session cookies */ - !co->expires) { /* this is a session cookie since it doesn't expire! */ - freecookie(co); - return NULL; - } - - co->livecookie = c->running; - - /* now, we have parsed the incoming line, we must now check if this - superceeds an already existing cookie, which it may if the previous have - the same domain and path as this */ - - clist = c->cookies; - replace_old = FALSE; - while(clist) { - if(strequal(clist->name, co->name)) { - /* the names are identical */ - - if(clist->domain && co->domain) { - if(strequal(clist->domain, co->domain)) - /* The domains are identical */ - replace_old=TRUE; - } - else if(!clist->domain && !co->domain) - replace_old = TRUE; - - if(replace_old) { - /* the domains were identical */ - - if(clist->path && co->path) { - if(strequal(clist->path, co->path)) { - replace_old = TRUE; - } - else - replace_old = FALSE; - } - else if(!clist->path && !co->path) - replace_old = TRUE; - else - replace_old = FALSE; - - } - - 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 isn't "live" and thus only read from a file. We let - live cookies stay alive */ - - /* Free the newcomer and get out of here! */ - freecookie(co); - return NULL; - } - - if(replace_old) { - co->next = clist->next; /* get the next-pointer first */ - - /* then free all the old pointers */ - if(clist->name) - free(clist->name); - if(clist->value) - free(clist->value); - if(clist->domain) - free(clist->domain); - if(clist->path) - free(clist->path); - if(clist->expirestr) - free(clist->expirestr); - - if(clist->version) - free(clist->version); - if(clist->maxage) - free(clist->maxage); - - *clist = *co; /* then store all the new data */ - - free(co); /* free the newly alloced memory */ - co = clist; /* point to the previous struct instead */ - - /* We have replaced a cookie, now skip the rest of the list but - make sure the 'lastc' pointer is properly set */ - do { - lastc = clist; - clist = clist->next; - } while(clist); - break; - } - } - lastc = clist; - clist = clist->next; - } - - 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 %d\n", - replace_old?"Replaced":"Added", co->name, co->value, - co->domain, co->path, co->expires); - - if(!replace_old) { - /* then make the last item point on this new one */ - if(lastc) - lastc->next = co; - else - c->cookies = co; - } - - c->numcookies++; /* one more cookie in the jar */ - return co; -} - -/***************************************************************************** - * - * Curl_cookie_init() - * - * Inits a cookie struct to read data from a local file. This is always - * called before any cookies are set. File may be NULL. - * - * If 'newsession' is TRUE, discard all "session cookies" on read from file. - * - ****************************************************************************/ -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, - char *file, - struct CookieInfo *inc, - bool newsession) -{ - struct CookieInfo *c; - FILE *fp; - bool fromfile=TRUE; - - if(NULL == inc) { - /* we didn't get a struct, create one */ - c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo)); - if(!c) - return NULL; /* failed to get memory */ - c->filename = strdup(file?file:"none"); /* copy the name just in case */ - } - else { - /* we got an already existing one, use that */ - c = inc; - } - c->running = FALSE; /* this is not running, this is init */ - - if(file && strequal(file, "-")) { - fp = stdin; - fromfile=FALSE; - } - else if(file && !*file) { - /* points to a "" string */ - fp = NULL; - } - else - fp = file?fopen(file, "r"):NULL; - - c->newsession = newsession; /* new session? */ - - if(fp) { - char *lineptr; - bool headerline; - - char *line = (char *)malloc(MAX_COOKIE_LINE); - if(line) { - while(fgets(line, MAX_COOKIE_LINE, fp)) { - if(checkprefix("Set-Cookie:", line)) { - /* This is a cookie line, get it! */ - lineptr=&line[11]; - headerline=TRUE; - } - else { - lineptr=line; - headerline=FALSE; - } - while(*lineptr && my_isspace(*lineptr)) - lineptr++; - - Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); - } - free(line); /* free the line buffer */ - } - if(fromfile) - fclose(fp); - } - - c->running = TRUE; /* now, we're running */ - - return c; -} - -/***************************************************************************** - * - * Curl_cookie_getlist() - * - * For a given host and path, return a linked list of cookies that the - * client 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 haven't expired. - * - ****************************************************************************/ - -struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, - char *host, char *path, bool secure) -{ - struct Cookie *newco; - struct Cookie *co; - time_t now = time(NULL); - struct Cookie *mainco=NULL; - - if(!c || !c->cookies) - return NULL; /* no cookie struct or no cookies in the struct */ - - co = c->cookies; - - while(co) { - /* only process this cookie if it is not expired or had no expire - date AND that if the cookie requires we're secure we must only - continue if we are! */ - if( (co->expires<=0 || (co->expires> now)) && - (co->secure?secure:TRUE) ) { - - /* now check if the domain is correct */ - if(!co->domain || - (co->tailmatch && tailmatch(co->domain, host)) || - (!co->tailmatch && strequal(host, co->domain)) ) { - /* the right part of the host matches the domain stuff in the - cookie data */ - - /* now check the left part of the path with the cookies path - requirement */ - if(!co->path || - /* not using checkprefix() because matching should be - case-sensitive */ - !strncmp(co->path, path, strlen(co->path)) ) { - - /* and now, we know this is a match and we should create an - entry for the return-linked-list */ - - newco = (struct Cookie *)malloc(sizeof(struct Cookie)); - if(newco) { - /* first, copy the whole source cookie: */ - memcpy(newco, co, sizeof(struct Cookie)); - - /* then modify our next */ - newco->next = mainco; - - /* point the main to us */ - mainco = newco; - } - else { - /* failure, clear up the allocated chain and return NULL */ - while(mainco) { - co = mainco->next; - free(mainco); - mainco = co; - } - - return NULL; - } - } - } - } - co = co->next; - } - - return mainco; /* return the new list */ -} - -/***************************************************************************** - * - * Curl_cookie_clearall() - * - * Clear all existing cookies and reset the counter. - * - ****************************************************************************/ -void Curl_cookie_clearall(struct CookieInfo *cookies) -{ - if(cookies) { - Curl_cookie_freelist(cookies->cookies); - cookies->cookies = NULL; - cookies->numcookies = 0; - } -} - -/***************************************************************************** - * - * Curl_cookie_freelist() - * - * Free a list of cookies previously returned by Curl_cookie_getlist(); - * - ****************************************************************************/ - -void Curl_cookie_freelist(struct Cookie *co) -{ - struct Cookie *next; - if(co) { - while(co) { - next = co->next; - free(co); /* we only free the struct since the "members" are all - just copied! */ - co = next; - } - } -} - - -/***************************************************************************** - * - * Curl_cookie_clearsess() - * - * Free all session cookies in the cookies list. - * - ****************************************************************************/ -void Curl_cookie_clearsess(struct CookieInfo *cookies) -{ - struct Cookie *first, *curr, *next, *prev = NULL; - - if(!cookies->cookies) - return; - - first = curr = prev = cookies->cookies; - - for(; curr; curr = next) { - next = curr->next; - if(!curr->expires) { - if(first == curr) - first = next; - - if(prev == curr) - prev = next; - else - prev->next = next; - - free(curr); - cookies->numcookies--; - } - else - prev = curr; - } - - cookies->cookies = first; -} - - -/***************************************************************************** - * - * Curl_cookie_cleanup() - * - * Free a "cookie object" previous created with cookie_init(). - * - ****************************************************************************/ -void Curl_cookie_cleanup(struct CookieInfo *c) -{ - struct Cookie *co; - struct Cookie *next; - if(c) { - if(c->filename) - free(c->filename); - co = c->cookies; - - while(co) { - next = co->next; - freecookie(co); - co = next; - } - free(c); /* free the base struct as well */ - } -} - -/* get_netscape_format() - * - * Formats a string for Netscape output file, w/o a newline at the end. - * - * Function returns a char * to a formatted line. Has to be free()d -*/ -static char *get_netscape_format(const struct Cookie *co) -{ - return aprintf( - "%s%s\t" /* domain */ - "%s\t" /* tailmatch */ - "%s\t" /* path */ - "%s\t" /* secure */ - "%" FORMAT_OFF_T "\t" /* expires */ - "%s\t" /* name */ - "%s", /* value */ - /* Make sure all domains are prefixed with a dot if they allow - tailmatching. This is Mozilla-style. */ - (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"", - co->domain?co->domain:"unknown", - co->tailmatch?"TRUE":"FALSE", - co->path?co->path:"/", - co->secure?"TRUE":"FALSE", - co->expires, - co->name, - co->value?co->value:""); -} - -/* - * Curl_cookie_output() - * - * Writes all internally known cookies to the specified file. Specify - * "-" as file name to write to stdout. - * - * The function returns non-zero on write failure. - */ -int Curl_cookie_output(struct CookieInfo *c, char *dumphere) -{ - struct Cookie *co; - FILE *out; - bool use_stdout=FALSE; - - if((NULL == c) || (0 == c->numcookies)) - /* If there are no known cookies, we don't write or even create any - destination file */ - return 0; - - if(strequal("-", dumphere)) { - /* use stdout */ - out = stdout; - use_stdout=TRUE; - } - else { - out = fopen(dumphere, "w"); - if(!out) - return 1; /* failure */ - } - - if(c) { - char *format_ptr; - - fputs("# Netscape HTTP Cookie File\n" - "# http://curlm.haxx.se/rfc/cookie_spec.html\n" - "# This file was generated by libcurl! Edit at your own risk.\n\n", - out); - co = c->cookies; - - while(co) { - format_ptr = get_netscape_format(co); - if (format_ptr == NULL) { - fprintf(out, "#\n# Fatal libcurl error\n"); - if(!use_stdout) - fclose(out); - return 1; - } - fprintf(out, "%s\n", format_ptr); - free(format_ptr); - co=co->next; - } - } - - if(!use_stdout) - fclose(out); - - return 0; -} - -struct curl_slist *Curl_cookie_list(struct SessionHandle *data) -{ - struct curl_slist *list = NULL; - struct curl_slist *beg; - struct Cookie *c; - char *line; - - if ((data->cookies == NULL) || - (data->cookies->numcookies == 0)) - return NULL; - - c = data->cookies->cookies; - - beg = list; - while (c) { - /* fill the list with _all_ the cookies we know */ - line = get_netscape_format(c); - if (line == NULL) { - /* get_netscape_format returns null only if we run out of memory */ - - curl_slist_free_all(beg); /* free some memory */ - return NULL; - } - list = curl_slist_append(list, line); - free(line); - c = c->next; - } - - return list; -} - -#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ diff --git a/Utilities/cmcurl/cookie.h b/Utilities/cmcurl/cookie.h deleted file mode 100644 index 57c3acb..0000000 --- a/Utilities/cmcurl/cookie.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef __COOKIE_H -#define __COOKIE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include -#if defined(WIN32) -#include -#else -#ifdef HAVE_SYS_TIME_H -#include -#endif -#endif - -#include - -struct Cookie { - struct Cookie *next; /* next in the chain */ - char *name; /* = value */ - char *value; /* name = */ - char *path; /* path = */ - char *domain; /* domain = */ - curl_off_t expires; /* expires = */ - char *expirestr; /* the plain text version */ - bool tailmatch; /* weather we do tail-matchning of the domain name */ - - /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ - char *version; /* Version = */ - char *maxage; /* Max-Age = */ - - bool secure; /* whether the 'secure' keyword was used */ - bool livecookie; /* updated from a server, not a stored file */ -}; - -struct CookieInfo { - /* linked list of cookies we know of */ - struct Cookie *cookies; - - char *filename; /* file we read from/write to */ - bool running; /* state info, for cookie adding information */ - long numcookies; /* number of cookies in the "jar" */ - bool newsession; /* new session, discard session cookies on load */ -}; - -/* This is the maximum line length we accept for a cookie line. RFC 2109 - section 6.3 says: - - "at least 4096 bytes per cookie (as measured by the size of the characters - that comprise the cookie non-terminal in the syntax description of the - Set-Cookie header)" - -*/ -#define MAX_COOKIE_LINE 5000 -#define MAX_COOKIE_LINE_TXT "4999" - -/* This is the maximum length of a cookie name we deal with: */ -#define MAX_NAME 1024 -#define MAX_NAME_TXT "1023" - -struct SessionHandle; -/* - * Add a cookie to the internal list of cookies. The domain and path arguments - * are only used if the header boolean is TRUE. - */ - -struct Cookie *Curl_cookie_add(struct SessionHandle *data, - struct CookieInfo *, bool header, char *line, - char *domain, char *path); - -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, - char *, struct CookieInfo *, bool); -struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool); -void Curl_cookie_freelist(struct Cookie *); -void Curl_cookie_clearall(struct CookieInfo *cookies); -void Curl_cookie_clearsess(struct CookieInfo *cookies); -void Curl_cookie_cleanup(struct CookieInfo *); -int Curl_cookie_output(struct CookieInfo *, char *); - -#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) -#define Curl_cookie_list(x) NULL -#define Curl_cookie_loadfiles(x) do { } while (0) -#else -struct curl_slist *Curl_cookie_list(struct SessionHandle *data); -void Curl_cookie_loadfiles(struct SessionHandle *data); -#endif - -#endif diff --git a/Utilities/cmcurl/curl/curl.h b/Utilities/cmcurl/curl/curl.h deleted file mode 100644 index e586c4a..0000000 --- a/Utilities/cmcurl/curl/curl.h +++ /dev/null @@ -1,1644 +0,0 @@ -#ifndef __CURL_CURL_H -#define __CURL_CURL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* If you have problems, all libcurl docs and details are found here: - http://curl.haxx.se/libcurl/ -*/ - -#include "curlver.h" /* the libcurl version defines */ - -#include -#include - -/* The include stuff here below is mainly for time_t! */ -#ifdef vms -# include -# include -#else -# include -# include -#endif /* defined (vms) */ - -typedef void CURL; - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Decorate exportable functions for Win32 DLL linking. - * This avoids using a .def file for building libcurl.dll. - */ -#if (defined(WIN32) || defined(_WIN32)) && !defined(CURL_STATICLIB) -#if defined(BUILDING_LIBCURL) -#define CURL_EXTERN __declspec(dllexport) -#else -#define CURL_EXTERN __declspec(dllimport) -#endif -#else - -#ifdef CURL_HIDDEN_SYMBOLS -/* - * This definition is used to make external definitions visibile in the - * shared library when symbols are hidden by default. It makes no - * difference when compiling applications whether this is set or not, - * only when compiling the library. - */ -#define CURL_EXTERN CURL_EXTERN_SYMBOL -#else -#define CURL_EXTERN -#endif -#endif - -/* - * We want the typedef curl_off_t setup for large file support on all - * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf - * format strings when outputting a variable of type curl_off_t. - * - * Note: "pocc -Ze" is MSVC compatibily mode and this sets _MSC_VER! - */ - -#if (defined(_MSC_VER) && !defined(__POCC__)) || (defined(__LCC__) && defined(WIN32)) -/* MSVC */ -#ifdef _WIN32_WCE - typedef long curl_off_t; -#define CURL_FORMAT_OFF_T "%ld" -#else - typedef signed __int64 curl_off_t; -#define CURL_FORMAT_OFF_T "%I64d" -#endif -#else /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */ -#if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__) -/* gcc on windows or Watcom */ - typedef long long curl_off_t; -#define CURL_FORMAT_OFF_T "%I64d" -#else /* GCC or Watcom on Windows */ - -/* "normal" POSIX approach, do note that this does not necessarily mean that - the type is >32 bits, see the SIZEOF_CURL_OFF_T define for that! */ - typedef off_t curl_off_t; - -/* Check a range of defines to detect large file support. On Linux it seems - none of these are set by default, so if you don't explicitly switches on - large file support, this define will be made for "small file" support. */ -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 0 /* to prevent warnings in the check below */ -#define UNDEF_FILE_OFFSET_BITS -#endif -#ifndef FILESIZEBITS -#define FILESIZEBITS 0 /* to prevent warnings in the check below */ -#define UNDEF_FILESIZEBITS -#endif - -#if defined(_LARGE_FILES) || (_FILE_OFFSET_BITS > 32) || (FILESIZEBITS > 32) \ - || defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE) - /* For now, we assume at least one of these to be set for large files to - work! */ -#define CURL_FORMAT_OFF_T "%lld" -#else /* LARGE_FILE support */ -#define CURL_FORMAT_OFF_T "%ld" -#endif -#endif /* GCC or Watcom on Windows */ -#endif /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */ - -#ifdef UNDEF_FILE_OFFSET_BITS -/* this was defined above for our checks, undefine it again */ -#undef _FILE_OFFSET_BITS -#endif - -#ifdef UNDEF_FILESIZEBITS -/* this was defined above for our checks, undefine it again */ -#undef FILESIZEBITS -#endif - -#if defined(_WIN32) && !defined(WIN32) -/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we - make this adjustment to catch this. */ -#define WIN32 1 -#endif - -#ifdef __cplusplus -} -#endif - -#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \ - !defined(__CYGWIN__) || defined(__MINGW32__) -#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H)) -/* The check above prevents the winsock2 inclusion if winsock.h already was - included, since they can't co-exist without problems */ -#include -#endif -#else - -/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish - libc5-based Linux systems. Only include it on system that are known to - require it! */ -#if defined(_AIX) || defined(NETWARE) || defined(__NetBSD__) || defined(__minix) -#include -#endif - -#ifndef _WIN32_WCE -#include -#endif -#ifndef __WATCOMC__ -#include -#endif -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef curl_socket_typedef -/* socket typedef */ -#ifdef WIN32 -typedef SOCKET curl_socket_t; -#define CURL_SOCKET_BAD INVALID_SOCKET -#else -typedef int curl_socket_t; -#define CURL_SOCKET_BAD -1 -#endif -#define curl_socket_typedef -#endif /* curl_socket_typedef */ - -struct curl_httppost { - struct curl_httppost *next; /* next entry in the list */ - char *name; /* pointer to allocated name */ - long namelength; /* length of name length */ - char *contents; /* pointer to allocated data contents */ - long contentslength; /* length of contents field */ - char *buffer; /* pointer to allocated buffer contents */ - long bufferlength; /* length of buffer field */ - char *contenttype; /* Content-Type */ - struct curl_slist* contentheader; /* list of extra headers for this form */ - struct curl_httppost *more; /* if one field name has more than one - file, this link should link to following - files */ - long flags; /* as defined below */ -#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ -#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ -#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer - do not free in formfree */ -#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer - do not free in formfree */ -#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ -#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ - - char *showfilename; /* The file name to show. If not set, the - actual file name will be used (if this - is a file part) */ -}; - -typedef int (*curl_progress_callback)(void *clientp, - double dltotal, - double dlnow, - double ultotal, - double ulnow); - - /* Tests have proven that 20K is a very bad buffer size for uploads on - Windows, while 16K for some odd reason performed a lot better. */ -#define CURL_MAX_WRITE_SIZE 16384 - -typedef size_t (*curl_write_callback)(char *buffer, - size_t size, - size_t nitems, - void *outstream); - -/* This is a return code for the read callback that, when returned, will - signal libcurl to immediately abort the current transfer. */ -#define CURL_READFUNC_ABORT 0x10000000 -typedef size_t (*curl_read_callback)(char *buffer, - size_t size, - size_t nitems, - void *instream); - -typedef enum { - CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ - CURLSOCKTYPE_LAST /* never use */ -} curlsocktype; - -typedef int (*curl_sockopt_callback)(void *clientp, - curl_socket_t curlfd, - curlsocktype purpose); - -#ifndef CURL_NO_OLDIES - /* not used since 7.10.8, will be removed in a future release */ -typedef int (*curl_passwd_callback)(void *clientp, - const char *prompt, - char *buffer, - int buflen); -#endif - -typedef enum { - CURLIOE_OK, /* I/O operation successful */ - CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ - CURLIOE_FAILRESTART, /* failed to restart the read */ - CURLIOE_LAST /* never use */ -} curlioerr; - -typedef enum { - CURLIOCMD_NOP, /* no operation */ - CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ - CURLIOCMD_LAST /* never use */ -} curliocmd; - -typedef curlioerr (*curl_ioctl_callback)(CURL *handle, - int cmd, - void *clientp); - -/* - * The following typedef's are signatures of malloc, free, realloc, strdup and - * 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. - */ -typedef void *(*curl_malloc_callback)(size_t size); -typedef void (*curl_free_callback)(void *ptr); -typedef void *(*curl_realloc_callback)(void *ptr, size_t size); -typedef char *(*curl_strdup_callback)(const char *str); -typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); - -/* the kind of data that is passed to information_callback*/ -typedef enum { - CURLINFO_TEXT = 0, - CURLINFO_HEADER_IN, /* 1 */ - CURLINFO_HEADER_OUT, /* 2 */ - CURLINFO_DATA_IN, /* 3 */ - CURLINFO_DATA_OUT, /* 4 */ - CURLINFO_SSL_DATA_IN, /* 5 */ - CURLINFO_SSL_DATA_OUT, /* 6 */ - CURLINFO_END -} curl_infotype; - -typedef int (*curl_debug_callback) - (CURL *handle, /* the handle/transfer this concerns */ - curl_infotype type, /* what kind of data */ - char *data, /* points to the data */ - size_t size, /* size of the data pointed to */ - void *userptr); /* whatever the user please */ - -/* All possible error codes from all sorts of curl functions. Future versions - may return other values, stay prepared. - - Always add new return codes last. Never *EVER* remove any. The return - codes must remain the same! - */ - -typedef enum { - CURLE_OK = 0, - CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ - CURLE_FAILED_INIT, /* 2 */ - CURLE_URL_MALFORMAT, /* 3 */ - CURLE_NOT_BUILT_IN, /* 4 */ - CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ - CURLE_COULDNT_RESOLVE_HOST, /* 6 */ - CURLE_COULDNT_CONNECT, /* 7 */ - CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ - CURLE_FTP_ACCESS_DENIED, /* 9 a service was denied by the FTP server - due to lack of access - when login fails - this is not returned. */ - CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 - NOT USED */ - CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ - CURLE_FTP_WEIRD_USER_REPLY, /* 12 */ - CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ - CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ - CURLE_FTP_CANT_GET_HOST, /* 15 */ - CURLE_FTP_CANT_RECONNECT, /* 16 */ - CURLE_FTP_COULDNT_SET_BINARY, /* 17 */ - CURLE_PARTIAL_FILE, /* 18 */ - CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ - CURLE_FTP_WRITE_ERROR, /* 20 */ - CURLE_FTP_QUOTE_ERROR, /* 21 */ - CURLE_HTTP_RETURNED_ERROR, /* 22 */ - CURLE_WRITE_ERROR, /* 23 */ - CURLE_MALFORMAT_USER, /* 24 - NOT USED */ - CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */ - CURLE_READ_ERROR, /* 26 - could open/read from file */ - CURLE_OUT_OF_MEMORY, /* 27 */ - /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error - instead of a memory allocation error if CURL_DOES_CONVERSIONS - is defined - */ - CURLE_OPERATION_TIMEOUTED, /* 28 - the timeout time was reached */ - CURLE_FTP_COULDNT_SET_ASCII, /* 29 - TYPE A failed */ - CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ - CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ - CURLE_FTP_COULDNT_GET_SIZE, /* 32 - the SIZE command failed */ - CURLE_HTTP_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 - couldn't resume download */ - CURLE_FILE_COULDNT_READ_FILE, /* 37 */ - CURLE_LDAP_CANNOT_BIND, /* 38 */ - CURLE_LDAP_SEARCH_FAILED, /* 39 */ - CURLE_LIBRARY_NOT_FOUND, /* 40 */ - CURLE_FUNCTION_NOT_FOUND, /* 41 */ - CURLE_ABORTED_BY_CALLBACK, /* 42 */ - CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ - CURLE_BAD_CALLING_ORDER, /* 44 - NOT USED */ - CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ - CURLE_BAD_PASSWORD_ENTERED, /* 46 - NOT USED */ - CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ - CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */ - CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ - CURLE_OBSOLETE, /* 50 - NOT USED */ - CURLE_SSL_PEER_CERTIFICATE, /* 51 - peer's certificate wasn't ok */ - CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ - CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ - CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as - default */ - CURLE_SEND_ERROR, /* 55 - failed sending network data */ - CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ - CURLE_SHARE_IN_USE, /* 57 - share is in use */ - CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ - CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ - CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ - CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */ - CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ - CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ - CURLE_FTP_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ - CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind - that failed */ - CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ - CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not - accepted and we failed to login */ - CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ - CURLE_TFTP_PERM, /* 69 - permission problem on server */ - CURLE_TFTP_DISKFULL, /* 70 - out of disk space on server */ - CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ - CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ - CURLE_TFTP_EXISTS, /* 73 - File already exists */ - CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ - CURLE_CONV_FAILED, /* 75 - conversion failed */ - CURLE_CONV_REQD, /* 76 - caller must register conversion - callbacks using curl_easy_setopt options - CURLOPT_CONV_FROM_NETWORK_FUNCTION, - CURLOPT_CONV_TO_NETWORK_FUNCTION, and - CURLOPT_CONV_FROM_UTF8_FUNCTION */ - CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing - or wrong format */ - CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ - CURLE_SSH, /* 79 - error from the SSH layer, somewhat - generic so the error message will be of - interest when this has happened */ - - CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL - connection */ - CURL_LAST /* never use! */ -} CURLcode; - -/* This prototype applies to all conversion callbacks */ -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 SSL_CTX */ - void *userptr); - -/* Make a spelling correction for the operation timed-out define */ -#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED - -#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all - the obsolete stuff removed! */ -/* backwards compatibility with older names */ -#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR -#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED -#endif - -typedef enum { - CURLPROXY_HTTP = 0, - CURLPROXY_SOCKS4 = 4, - CURLPROXY_SOCKS5 = 5 -} curl_proxytype; - -#define CURLAUTH_NONE 0 /* nothing */ -#define CURLAUTH_BASIC (1<<0) /* Basic (default) */ -#define CURLAUTH_DIGEST (1<<1) /* Digest */ -#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */ -#define CURLAUTH_NTLM (1<<3) /* NTLM */ -#define CURLAUTH_ANY ~0 /* all types set */ -#define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC) - -#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ -#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ -#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ -#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ -#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ -#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ -#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY - -#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all - the obsolete stuff removed! */ -/* this was the error code 50 in 7.7.3 and a few earlier versions, this - is no longer used by libcurl but is instead #defined here only to not - make programs break */ -#define CURLE_ALREADY_COMPLETE 99999 - -/* These are just to make older programs not break: */ -#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE -#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME -#endif - -#define CURL_ERROR_SIZE 256 - -/* parameter for the CURLOPT_FTP_SSL option */ -typedef enum { - CURLFTPSSL_NONE, /* do not attempt to use SSL */ - CURLFTPSSL_TRY, /* try using SSL, proceed anyway otherwise */ - CURLFTPSSL_CONTROL, /* SSL for the control connection or fail */ - CURLFTPSSL_ALL, /* SSL for all communication or fail */ - CURLFTPSSL_LAST /* not an option, never use */ -} curl_ftpssl; - -/* parameter for the CURLOPT_FTPSSLAUTH option */ -typedef enum { - CURLFTPAUTH_DEFAULT, /* let libcurl decide */ - CURLFTPAUTH_SSL, /* use "AUTH SSL" */ - CURLFTPAUTH_TLS, /* use "AUTH TLS" */ - CURLFTPAUTH_LAST /* not an option, never use */ -} curl_ftpauth; - -/* parameter for the CURLOPT_FTP_FILEMETHOD option */ -typedef enum { - CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ - CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ - CURLFTPMETHOD_NOCWD, /* no CWD at all */ - CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ - CURLFTPMETHOD_LAST /* not an option, never use */ -} curl_ftpmethod; - -/* long may be 32 or 64 bits, but we should never depend on anything else - but 32 */ -#define CURLOPTTYPE_LONG 0 -#define CURLOPTTYPE_OBJECTPOINT 10000 -#define CURLOPTTYPE_FUNCTIONPOINT 20000 -#define CURLOPTTYPE_OFF_T 30000 - -/* name is uppercase CURLOPT_, - type is one of the defined CURLOPTTYPE_ - number is unique identifier */ -#ifdef CINIT -#undef CINIT -#endif -/* - * Figure out if we can use the ## operator, which is supported by ISO/ANSI C - * and C++. Some compilers support it without setting __STDC__ or __cplusplus - * so we need to carefully check for them too. We don't use configure-checks - * for these since we want these headers to remain generic and working for all - * platforms. - */ -#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ - defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ - defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) - /* This compiler is believed to have an ISO compatible preprocessor */ -#define CURL_ISOCPP -#else - /* This compiler is believed NOT to have an ISO compatible preprocessor */ -#undef CURL_ISOCPP -#endif - -#ifdef CURL_ISOCPP -#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define LONG CURLOPTTYPE_LONG -#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT -#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT -#define OFF_T CURLOPTTYPE_OFF_T -#define CINIT(name,type,number) CURLOPT_/**/name = type + number -#endif - -/* - * This macro-mania below setups the CURLOPT_[what] enum, to be used with - * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] - * word. - */ - -typedef enum { - /* This is the FILE * or void * the regular output should be written to. */ - CINIT(FILE, OBJECTPOINT, 1), - - /* The full URL to get/put */ - CINIT(URL, OBJECTPOINT, 2), - - /* Port number to connect to, if other than default. */ - CINIT(PORT, LONG, 3), - - /* Name of proxy to use. */ - CINIT(PROXY, OBJECTPOINT, 4), - - /* "name:password" to use when fetching. */ - CINIT(USERPWD, OBJECTPOINT, 5), - - /* "name:password" to use with proxy. */ - CINIT(PROXYUSERPWD, OBJECTPOINT, 6), - - /* Range to get, specified as an ASCII string. */ - CINIT(RANGE, OBJECTPOINT, 7), - - /* not used */ - - /* Specified file stream to upload from (use as input): */ - CINIT(INFILE, OBJECTPOINT, 9), - - /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE - * bytes big. If this is not used, error messages go to stderr instead: */ - CINIT(ERRORBUFFER, OBJECTPOINT, 10), - - /* Function that will be called to store the output (instead of fwrite). The - * parameters will use fwrite() syntax, make sure to follow them. */ - CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), - - /* Function that will be called to read the input (instead of fread). The - * parameters will use fread() syntax, make sure to follow them. */ - CINIT(READFUNCTION, FUNCTIONPOINT, 12), - - /* Time-out the read operation after this amount of seconds */ - CINIT(TIMEOUT, LONG, 13), - - /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about - * how large the file being sent really is. That allows better error - * checking and better verifies that the upload was succcessful. -1 means - * unknown size. - * - * 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. - */ - CINIT(INFILESIZE, LONG, 14), - - /* POST input fields. */ - CINIT(POSTFIELDS, OBJECTPOINT, 15), - - /* Set the referer page (needed by some CGIs) */ - CINIT(REFERER, OBJECTPOINT, 16), - - /* Set the FTP PORT string (interface name, named or numerical IP address) - Use i.e '-' to use default address. */ - CINIT(FTPPORT, OBJECTPOINT, 17), - - /* Set the User-Agent string (examined by some CGIs) */ - CINIT(USERAGENT, OBJECTPOINT, 18), - - /* If the download receives less than "low speed limit" bytes/second - * during "low speed time" seconds, the operations is aborted. - * You could i.e if you have a pretty high speed connection, abort if - * it is less than 2000 bytes/sec during 20 seconds. - */ - - /* Set the "low speed limit" */ - CINIT(LOW_SPEED_LIMIT, LONG , 19), - - /* Set the "low speed time" */ - CINIT(LOW_SPEED_TIME, LONG, 20), - - /* Set the continuation offset. - * - * 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. - */ - CINIT(RESUME_FROM, LONG, 21), - - /* Set cookie in request: */ - CINIT(COOKIE, OBJECTPOINT, 22), - - /* This points to a linked list of headers, struct curl_slist kind */ - CINIT(HTTPHEADER, OBJECTPOINT, 23), - - /* This points to a linked list of post entries, struct HttpPost */ - CINIT(HTTPPOST, OBJECTPOINT, 24), - - /* name of the file keeping your private SSL-certificate */ - CINIT(SSLCERT, OBJECTPOINT, 25), - - /* password for the SSL-private key, keep this for compatibility */ - CINIT(SSLCERTPASSWD, OBJECTPOINT, 26), - /* password for the SSL private key */ - CINIT(SSLKEYPASSWD, OBJECTPOINT, 26), - - /* send TYPE parameter? */ - CINIT(CRLF, LONG, 27), - - /* send linked-list of QUOTE commands */ - CINIT(QUOTE, OBJECTPOINT, 28), - - /* send FILE * or void * to store headers to, if you use a callback it - is simply passed to the callback unmodified */ - CINIT(WRITEHEADER, OBJECTPOINT, 29), - - /* point to a file to read the initial cookies from, also enables - "cookie awareness" */ - CINIT(COOKIEFILE, OBJECTPOINT, 31), - - /* What version to specifly try to use. - See CURL_SSLVERSION defines below. */ - CINIT(SSLVERSION, LONG, 32), - - /* What kind of HTTP time condition to use, see defines */ - CINIT(TIMECONDITION, LONG, 33), - - /* Time to use with the above condition. Specified in number of seconds - since 1 Jan 1970 */ - CINIT(TIMEVALUE, LONG, 34), - - /* 35 = OBSOLETE */ - - /* Custom request, for customizing the get command like - HTTP: DELETE, TRACE and others - FTP: to use a different list command - */ - CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), - - /* HTTP request, for odd commands like DELETE, TRACE and others */ - CINIT(STDERR, OBJECTPOINT, 37), - - /* 38 is not used */ - - /* send linked-list of post-transfer QUOTE commands */ - CINIT(POSTQUOTE, OBJECTPOINT, 39), - - /* Pass a pointer to string of the output using full variable-replacement - as described elsewhere. */ - CINIT(WRITEINFO, OBJECTPOINT, 40), - - CINIT(VERBOSE, LONG, 41), /* talk a lot */ - CINIT(HEADER, LONG, 42), /* throw the header out too */ - CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ - CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ - CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ - CINIT(UPLOAD, LONG, 46), /* this is an upload */ - CINIT(POST, LONG, 47), /* HTTP POST method */ - CINIT(FTPLISTONLY, LONG, 48), /* Use NLST when listing ftp dir */ - - CINIT(FTPAPPEND, LONG, 50), /* Append instead of overwrite on upload! */ - - /* Specify whether to read the user+password from the .netrc or the URL. - * This must be one of the CURL_NETRC_* enums below. */ - CINIT(NETRC, LONG, 51), - - CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ - - CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ - CINIT(PUT, LONG, 54), /* HTTP PUT */ - - /* 55 = OBSOLETE */ - - /* Function that will be called instead of the internal progress display - * function. This function should be defined as the curl_progress_callback - * prototype defines. */ - CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), - - /* Data passed to the progress callback */ - CINIT(PROGRESSDATA, OBJECTPOINT, 57), - - /* We want the referer field set automatically when following locations */ - CINIT(AUTOREFERER, LONG, 58), - - /* Port of the proxy, can be set in the proxy string as well with: - "[host]:[port]" */ - CINIT(PROXYPORT, LONG, 59), - - /* size of the POST input data, if strlen() is not good to use */ - CINIT(POSTFIELDSIZE, LONG, 60), - - /* tunnel non-http operations through a HTTP proxy */ - CINIT(HTTPPROXYTUNNEL, LONG, 61), - - /* Set the interface string to use as outgoing network interface */ - CINIT(INTERFACE, OBJECTPOINT, 62), - - /* Set the krb4 security level, this also enables krb4 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. */ - CINIT(KRB4LEVEL, OBJECTPOINT, 63), - - /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ - CINIT(SSL_VERIFYPEER, LONG, 64), - - /* The CApath or CAfile used to validate the peer certificate - this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAINFO, OBJECTPOINT, 65), - - /* 66 = OBSOLETE */ - /* 67 = OBSOLETE */ - - /* Maximum number of http redirects to follow */ - CINIT(MAXREDIRS, LONG, 68), - - /* Pass a long set to 1 to get the date of the requested document (if - possible)! Pass a zero to shut it off. */ - CINIT(FILETIME, LONG, 69), - - /* This points to a linked list of telnet options */ - CINIT(TELNETOPTIONS, OBJECTPOINT, 70), - - /* Max amount of cached alive connections */ - CINIT(MAXCONNECTS, LONG, 71), - - /* What policy to use when closing connections when the cache is filled - up */ - CINIT(CLOSEPOLICY, LONG, 72), - - /* 73 = OBSOLETE */ - - /* Set to explicitly use a new connection for the upcoming transfer. - Do not use this unless you're absolutely sure of this, as it makes the - operation slower and is less friendly for the network. */ - CINIT(FRESH_CONNECT, LONG, 74), - - /* Set to explicitly forbid the upcoming transfer's connection to be re-used - 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. */ - CINIT(FORBID_REUSE, LONG, 75), - - /* Set to a file name that contains random data for libcurl to use to - seed the random engine when doing SSL connects. */ - CINIT(RANDOM_FILE, OBJECTPOINT, 76), - - /* Set to the Entropy Gathering Daemon socket pathname */ - CINIT(EGDSOCKET, OBJECTPOINT, 77), - - /* Time-out connect operations after this amount of seconds, if connects - are OK within this time, then fine... This only aborts the connect - phase. [Only works on unix-style/SIGALRM operating systems] */ - CINIT(CONNECTTIMEOUT, LONG, 78), - - /* Function that will be called to store headers (instead of fwrite). The - * parameters will use fwrite() syntax, make sure to follow them. */ - CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), - - /* Set this to force the HTTP request to get back to GET. Only really usable - if POST, PUT or a custom request have been used first. - */ - CINIT(HTTPGET, LONG, 80), - - /* Set if we should verify the Common name from the peer certificate in ssl - * handshake, set 1 to check existence, 2 to ensure that it matches the - * provided hostname. */ - CINIT(SSL_VERIFYHOST, LONG, 81), - - /* Specify which file name to write all known cookies in after completed - operation. Set file name to "-" (dash) to make it go to stdout. */ - CINIT(COOKIEJAR, OBJECTPOINT, 82), - - /* Specify which SSL ciphers to use */ - CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), - - /* Specify which HTTP version to use! This must be set to one of the - CURL_HTTP_VERSION* enums set below. */ - CINIT(HTTP_VERSION, LONG, 84), - - /* Specificly switch on or off the FTP engine's use of the EPSV command. By - default, that one will always be attempted before the more traditional - PASV command. */ - CINIT(FTP_USE_EPSV, LONG, 85), - - /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ - CINIT(SSLCERTTYPE, OBJECTPOINT, 86), - - /* name of the file keeping your private SSL-key */ - CINIT(SSLKEY, OBJECTPOINT, 87), - - /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ - CINIT(SSLKEYTYPE, OBJECTPOINT, 88), - - /* crypto engine for the SSL-sub system */ - CINIT(SSLENGINE, OBJECTPOINT, 89), - - /* set the crypto engine for the SSL-sub system as default - the param has no meaning... - */ - CINIT(SSLENGINE_DEFAULT, LONG, 90), - - /* Non-zero value means to use the global dns cache */ - CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To becomeO BSOLETE soon */ - - /* DNS cache timeout */ - CINIT(DNS_CACHE_TIMEOUT, LONG, 92), - - /* send linked-list of pre-transfer QUOTE commands (Wesley Laxton)*/ - CINIT(PREQUOTE, OBJECTPOINT, 93), - - /* set the debug function */ - CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), - - /* set the data for the debug function */ - CINIT(DEBUGDATA, OBJECTPOINT, 95), - - /* mark this as start of a cookie session */ - CINIT(COOKIESESSION, LONG, 96), - - /* The CApath directory used to validate the peer certificate - this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAPATH, OBJECTPOINT, 97), - - /* Instruct libcurl to use a smaller receive buffer */ - CINIT(BUFFERSIZE, LONG, 98), - - /* Instruct libcurl to not use any signal/alarm handlers, even when using - timeouts. This option is useful for multi-threaded applications. - See libcurl-the-guide for more background information. */ - CINIT(NOSIGNAL, LONG, 99), - - /* Provide a CURLShare for mutexing non-ts data */ - CINIT(SHARE, OBJECTPOINT, 100), - - /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), - CURLPROXY_SOCKS4 and CURLPROXY_SOCKS5. */ - CINIT(PROXYTYPE, LONG, 101), - - /* Set the Accept-Encoding string. Use this to tell a server you would like - the response to be compressed. */ - CINIT(ENCODING, OBJECTPOINT, 102), - - /* Set pointer to private data */ - CINIT(PRIVATE, OBJECTPOINT, 103), - - /* Set aliases for HTTP 200 in the HTTP Response header */ - CINIT(HTTP200ALIASES, OBJECTPOINT, 104), - - /* Continue to send authentication (user+password) when following locations, - even when hostname changed. This can potentionally send off the name - and password to whatever host the server decides. */ - CINIT(UNRESTRICTED_AUTH, LONG, 105), - - /* Specificly switch on or off the FTP engine's use of the EPRT command ( it - also disables the LPRT attempt). By default, those ones will always be - attempted before the good old traditional PORT command. */ - CINIT(FTP_USE_EPRT, LONG, 106), - - /* Set this to a bitmask value to enable the particular authentications - methods you like. Use this in combination with CURLOPT_USERPWD. - Note that setting multiple bits may cause extra network round-trips. */ - CINIT(HTTPAUTH, LONG, 107), - - /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx - in second argument. The function must be matching the - curl_ssl_ctx_callback proto. */ - CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), - - /* Set the userdata for the ssl context callback function's third - argument */ - CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), - - /* FTP Option that causes missing dirs to be created on the remote server */ - CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), - - /* Set this to a bitmask value to enable the particular authentications - methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. - Note that setting multiple bits may cause extra network round-trips. */ - CINIT(PROXYAUTH, LONG, 111), - - /* FTP option that changes the timeout, in seconds, associated with - getting a response. This is different from transfer timeout time and - essentially places a demand on the FTP server to acknowledge commands - in a timely manner. */ - CINIT(FTP_RESPONSE_TIMEOUT, LONG , 112), - - /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to - tell libcurl to resolve names to those IP versions only. This only has - affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ - CINIT(IPRESOLVE, LONG, 113), - - /* Set this option to limit the size of a file that will be downloaded from - 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. */ - CINIT(MAXFILESIZE, LONG, 114), - - /* See the comment for INFILESIZE above, but in short, specifies - * the size of the file being uploaded. -1 means unknown. - */ - CINIT(INFILESIZE_LARGE, OFF_T, 115), - - /* Sets the continuation offset. There is also a LONG version of this; - * look above for RESUME_FROM. - */ - CINIT(RESUME_FROM_LARGE, 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. - */ - CINIT(MAXFILESIZE_LARGE, OFF_T, 117), - - /* 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. */ - CINIT(NETRC_FILE, OBJECTPOINT, 118), - - /* Enable SSL/TLS for FTP, pick one of: - CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise - CURLFTPSSL_CONTROL - SSL for the control connection or fail - CURLFTPSSL_ALL - SSL for all communication or fail - */ - CINIT(FTP_SSL, LONG, 119), - - /* The _LARGE version of the standard POSTFIELDSIZE option */ - CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), - - /* Enable/disable the TCP Nagle algorithm */ - CINIT(TCP_NODELAY, LONG, 121), - - /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 123 OBSOLETE. Gone in 7.16.0 */ - /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ - /* 127 OBSOLETE. Gone in 7.16.0 */ - /* 128 OBSOLETE. Gone in 7.16.0 */ - - /* When FTP over SSL/TLS is selected (with CURLOPT_FTP_SSL), this option - can be used to change libcurl's default action which is to first try - "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK - response has been received. - - Available parameters are: - CURLFTPAUTH_DEFAULT - let libcurl decide - CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS - CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL - */ - CINIT(FTPSSLAUTH, LONG, 129), - - CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), - CINIT(IOCTLDATA, OBJECTPOINT, 131), - - /* 132 OBSOLETE. Gone in 7.16.0 */ - /* 133 OBSOLETE. Gone in 7.16.0 */ - - /* zero terminated string for pass on to the FTP server when asked for - "account" info */ - CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), - - /* feed cookies into cookie engine */ - CINIT(COOKIELIST, OBJECTPOINT, 135), - - /* ignore Content-Length */ - CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), - - /* Set to non-zero to skip the IP address received in a 227 PASV FTP server - response. Typically used for FTP-SSL purposes but is not restricted to - that. libcurl will then instead use the same IP address it used for the - control connection. */ - CINIT(FTP_SKIP_PASV_IP, LONG, 137), - - /* Select "file method" to use when doing FTP, see the curl_ftpmethod - above. */ - CINIT(FTP_FILEMETHOD, LONG, 138), - - /* Local port number to bind the socket to */ - CINIT(LOCALPORT, LONG, 139), - - /* Number of ports to try, including the first one set with LOCALPORT. - Thus, setting it to 1 will make no additional attempts but the first. - */ - CINIT(LOCALPORTRANGE, LONG, 140), - - /* no transfer, set up connection and let application use the socket by - extracting it with CURLINFO_LASTSOCKET */ - CINIT(CONNECT_ONLY, LONG, 141), - - /* Function that will be called to convert from the - network encoding (instead of using the iconv calls in libcurl) */ - CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), - - /* Function that will be called to convert to the - network encoding (instead of using the iconv calls in libcurl) */ - CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), - - /* Function that will be called to convert from UTF8 - (instead of using the iconv calls in libcurl) - Note that this is used only for SSL certificate processing */ - CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), - - /* if the connection proceeds too quickly then need to slow it down */ - /* limit-rate: maximum number of bytes per second to send or receive */ - CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), - CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), - - /* Pointer to command string to send if USER/PASS fails. */ - CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), - - /* callback function for setting socket options */ - CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), - CINIT(SOCKOPTDATA, OBJECTPOINT, 149), - - /* set to 0 to disable session ID re-use for this transfer, default is - enabled (== 1) */ - CINIT(SSL_SESSIONID_CACHE, LONG, 150), - - /* allowed SSH authentication methods */ - CINIT(SSH_AUTH_TYPES, LONG, 151), - - /* Used by scp/sftp to do public/private key authentication */ - CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), - CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), - - /* Send CCC (Clear Command Channel) after authentication */ - CINIT(FTP_SSL_CCC, LONG, 154), - - CURLOPT_LASTENTRY /* the last unused */ -} CURLoption; - - /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host - name resolves addresses using more than one IP protocol version, this - option might be handy to force libcurl to use a specific IP version. */ -#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP - versions that your system allows */ -#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ -#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ - - /* three convenient "aliases" that follow the name scheme better */ -#define CURLOPT_WRITEDATA CURLOPT_FILE -#define CURLOPT_READDATA CURLOPT_INFILE -#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER - -#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all - the obsolete stuff removed! */ -#else -/* This is set if CURL_NO_OLDIES is defined at compile-time */ -#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ -#endif - - - /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ -enum { - 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_LAST /* *ILLEGAL* http version */ -}; - - /* These enums are for use with the CURLOPT_NETRC option. */ -enum CURL_NETRC_OPTION { - CURL_NETRC_IGNORED, /* The .netrc will never be read. - * This is the default. */ - CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred - * to one in the .netrc. */ - CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. - * Unless one is set programmatically, the .netrc - * will be queried. */ - CURL_NETRC_LAST -}; - -enum { - CURL_SSLVERSION_DEFAULT, - CURL_SSLVERSION_TLSv1, - CURL_SSLVERSION_SSLv2, - CURL_SSLVERSION_SSLv3, - - CURL_SSLVERSION_LAST /* never use, keep last */ -}; - - -typedef enum { - CURL_TIMECOND_NONE, - - CURL_TIMECOND_IFMODSINCE, - CURL_TIMECOND_IFUNMODSINCE, - CURL_TIMECOND_LASTMOD, - - CURL_TIMECOND_LAST -} curl_TimeCond; - -#ifdef __cplusplus -} -#endif - -#if defined __BEOS__ || defined __HAIKU__ -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* curl_strequal() and curl_strnequal() are subject for removal in a future - libcurl, see lib/README.curlx for details */ -CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); -CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); - -/* name is uppercase CURLFORM_ */ -#ifdef CFINIT -#undef CFINIT -#endif - -#ifdef CURL_ISOCPP -#define CFINIT(name) CURLFORM_ ## name -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define CFINIT(name) CURLFORM_/**/name -#endif - -typedef enum { - CFINIT(NOTHING), /********* the first one is unused ************/ - - /* */ - CFINIT(COPYNAME), - CFINIT(PTRNAME), - CFINIT(NAMELENGTH), - CFINIT(COPYCONTENTS), - CFINIT(PTRCONTENTS), - CFINIT(CONTENTSLENGTH), - CFINIT(FILECONTENT), - CFINIT(ARRAY), - CFINIT(OBSOLETE), - CFINIT(FILE), - - CFINIT(BUFFER), - CFINIT(BUFFERPTR), - CFINIT(BUFFERLENGTH), - - CFINIT(CONTENTTYPE), - CFINIT(CONTENTHEADER), - CFINIT(FILENAME), - CFINIT(END), - CFINIT(OBSOLETE2), - - CURLFORM_LASTENTRY /* the last unusued */ -} CURLformoption; - -#undef CFINIT /* done */ - -/* structure to be used as parameter for CURLFORM_ARRAY */ -struct curl_forms { - CURLformoption option; - const char *value; -}; - -/* use this for multipart formpost building */ -/* Returns code for curl_formadd() - * - * Returns: - * CURL_FORMADD_OK on success - * CURL_FORMADD_MEMORY if the FormInfo allocation fails - * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form - * CURL_FORMADD_NULL if a null pointer was given for a char - * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed - * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used - * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) - * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated - * CURL_FORMADD_MEMORY if some allocation for string copying failed. - * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array - * - ***************************************************************************/ -typedef enum { - CURL_FORMADD_OK, /* first, no error */ - - CURL_FORMADD_MEMORY, - CURL_FORMADD_OPTION_TWICE, - CURL_FORMADD_NULL, - CURL_FORMADD_UNKNOWN_OPTION, - CURL_FORMADD_INCOMPLETE, - CURL_FORMADD_ILLEGAL_ARRAY, - CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ - - CURL_FORMADD_LAST /* last */ -} CURLFORMcode; - -/* - * NAME curl_formadd() - * - * DESCRIPTION - * - * Pretty advanved function for building multi-part formposts. Each invoke - * adds one part that together construct a full post. Then use - * CURLOPT_HTTPPOST to send it off to libcurl. - */ -CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...); - -/* - * callback function for curl_formget() - * The void *arg pointer will be the one passed as second argument to curl_formget(). - * The character buffer passed to it must not be freed. - * Should return the buffer length passed to it as the argument "len" on success. - */ -typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); - -/* - * NAME curl_formget() - * - * DESCRIPTION - * - * Serialize a curl_httppost struct built with curl_formadd(). - * Accepts a void pointer as second argument which will be passed to - * the curl_formget_callback function. - * Returns 0 on success. - */ -CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append); -/* - * NAME curl_formfree() - * - * DESCRIPTION - * - * Free a multipart formpost previously built with curl_formadd(). - */ -CURL_EXTERN void curl_formfree(struct curl_httppost *form); - -/* - * NAME curl_getenv() - * - * DESCRIPTION - * - * Returns a malloc()'ed string that MUST be curl_free()ed after usage is - * complete. DEPRECATED - see lib/README.curlx - */ -CURL_EXTERN char *curl_getenv(const char *variable); - -/* - * NAME curl_version() - * - * DESCRIPTION - * - * Returns a static ascii string of the libcurl version. - */ -CURL_EXTERN char *curl_version(void); - -/* - * NAME curl_easy_escape() - * - * DESCRIPTION - * - * Escapes URL strings (converts all letters consider illegal in URLs to their - * %XX versions). This function returns a new allocated string or NULL if an - * error occurred. - */ -CURL_EXTERN char *curl_easy_escape(CURL *handle, - const char *string, - int length); - -/* the previous version: */ -CURL_EXTERN char *curl_escape(const char *string, - int length); - - -/* - * NAME curl_easy_unescape() - * - * DESCRIPTION - * - * Unescapes URL encoding in strings (converts all %XX codes to their 8bit - * versions). This function returns a new allocated string or NULL if an error - * occurred. - * Conversion Note: On non-ASCII platforms the ASCII %XX codes are - * converted into the host encoding. - */ -CURL_EXTERN char *curl_easy_unescape(CURL *handle, - const char *string, - int length, - int *outlength); - -/* the previous version */ -CURL_EXTERN char *curl_unescape(const char *string, - int length); - -/* - * NAME curl_free() - * - * DESCRIPTION - * - * Provided for de-allocation in the same translation unit that did the - * allocation. Added in libcurl 7.10 - */ -CURL_EXTERN void curl_free(void *p); - -/* - * NAME curl_global_init() - * - * DESCRIPTION - * - * curl_global_init() should be invoked exactly once for each application that - * uses libcurl - */ -CURL_EXTERN CURLcode curl_global_init(long flags); - -/* - * NAME curl_global_init_mem() - * - * 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 - * 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 - * callback routines with be invoked by this library instead of the system - * memory management routines like malloc, free etc. - */ -CURL_EXTERN CURLcode curl_global_init_mem(long flags, - curl_malloc_callback m, - curl_free_callback f, - curl_realloc_callback r, - curl_strdup_callback s, - curl_calloc_callback c); - -/* - * NAME curl_global_cleanup() - * - * DESCRIPTION - * - * curl_global_cleanup() should be invoked exactly once for each application - * that uses libcurl - */ -CURL_EXTERN void curl_global_cleanup(void); - -/* linked-list structure for the CURLOPT_QUOTE option (and other) */ -struct curl_slist { - char *data; - struct curl_slist *next; -}; - -/* - * NAME curl_slist_append() - * - * DESCRIPTION - * - * Appends a string to a linked list. If no list exists, it will be created - * first. Returns the new list, after appending. - */ -CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, - const char *); - -/* - * NAME curl_slist_free_all() - * - * DESCRIPTION - * - * free a previously built curl_slist. - */ -CURL_EXTERN void curl_slist_free_all(struct curl_slist *); - -/* - * NAME curl_getdate() - * - * DESCRIPTION - * - * Returns the time, in seconds since 1 Jan 1970 of the time string given in - * the first argument. The time argument in the second parameter is unused - * and should be set to NULL. - */ -CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); - -#define CURLINFO_STRING 0x100000 -#define CURLINFO_LONG 0x200000 -#define CURLINFO_DOUBLE 0x300000 -#define CURLINFO_SLIST 0x400000 -#define CURLINFO_MASK 0x0fffff -#define CURLINFO_TYPEMASK 0xf00000 - -typedef enum { - CURLINFO_NONE, /* first, never use this */ - CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, - CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, - CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, - CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, - CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, - CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, - CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, - CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, - CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, - CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, - CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, - CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, - CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, - CURLINFO_FILETIME = CURLINFO_LONG + 14, - CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, - CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, - CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, - CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, - CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, - CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, - CURLINFO_PRIVATE = CURLINFO_STRING + 21, - CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, - CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, - CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, - CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, - CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, - CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, - CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, - CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, - CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, - /* Fill in new entries below here! */ - - CURLINFO_LASTONE = 30 -} CURLINFO; - -/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as - CURLINFO_HTTP_CODE */ -#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE - -typedef enum { - CURLCLOSEPOLICY_NONE, /* first, never use this */ - - CURLCLOSEPOLICY_OLDEST, - CURLCLOSEPOLICY_LEAST_RECENTLY_USED, - CURLCLOSEPOLICY_LEAST_TRAFFIC, - CURLCLOSEPOLICY_SLOWEST, - CURLCLOSEPOLICY_CALLBACK, - - CURLCLOSEPOLICY_LAST /* last, never use this */ -} curl_closepolicy; - -#define CURL_GLOBAL_SSL (1<<0) -#define CURL_GLOBAL_WIN32 (1<<1) -#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) -#define CURL_GLOBAL_NOTHING 0 -#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL - - -/***************************************************************************** - * Setup defines, protos etc for the sharing stuff. - */ - -/* Different data locks for a single share */ -typedef enum { - CURL_LOCK_DATA_NONE = 0, - /* CURL_LOCK_DATA_SHARE is used internaly to say that - * the locking is just made to change the internal state of the share - * itself. - */ - CURL_LOCK_DATA_SHARE, - CURL_LOCK_DATA_COOKIE, - CURL_LOCK_DATA_DNS, - CURL_LOCK_DATA_SSL_SESSION, - CURL_LOCK_DATA_CONNECT, - CURL_LOCK_DATA_LAST -} curl_lock_data; - -/* Different lock access types */ -typedef enum { - CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ - CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ - CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ - CURL_LOCK_ACCESS_LAST /* never use */ -} curl_lock_access; - -typedef void (*curl_lock_function)(CURL *handle, - curl_lock_data data, - curl_lock_access locktype, - void *userptr); -typedef void (*curl_unlock_function)(CURL *handle, - curl_lock_data data, - void *userptr); - -typedef void CURLSH; - -typedef enum { - CURLSHE_OK, /* all is fine */ - CURLSHE_BAD_OPTION, /* 1 */ - CURLSHE_IN_USE, /* 2 */ - CURLSHE_INVALID, /* 3 */ - CURLSHE_NOMEM, /* out of memory */ - CURLSHE_LAST /* never use */ -} CURLSHcode; - -typedef enum { - CURLSHOPT_NONE, /* don't use */ - CURLSHOPT_SHARE, /* specify a data type to share */ - CURLSHOPT_UNSHARE, /* specify shich data type to stop sharing */ - CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ - CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ - CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock - callback functions */ - CURLSHOPT_LAST /* never use */ -} CURLSHoption; - -CURL_EXTERN CURLSH *curl_share_init(void); -CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); -CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); - -/**************************************************************************** - * Structures for querying information about the curl library at runtime. - */ - -typedef enum { - CURLVERSION_FIRST, - CURLVERSION_SECOND, - CURLVERSION_THIRD, - CURLVERSION_FOURTH, - CURLVERSION_LAST /* never actually use this */ -} CURLversion; - -/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by - basicly all programs ever, that want to get version information. It is - 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_FOURTH - -typedef struct { - CURLversion age; /* age of the returned struct */ - const char *version; /* LIBCURL_VERSION */ - unsigned int version_num; /* LIBCURL_VERSION_NUM */ - const char *host; /* OS/host/cpu/machine when configured */ - int features; /* bitmask, see defines below */ - const char *ssl_version; /* human readable string */ - long ssl_version_num; /* not used anymore, always 0 */ - const char *libz_version; /* human readable string */ - /* protocols is terminated by an entry with a NULL protoname */ - const char * const *protocols; - - /* The fields below this were added in CURLVERSION_SECOND */ - const char *ares; - int ares_num; - - /* This field was added in CURLVERSION_THIRD */ - const char *libidn; - - /* These field were added in CURLVERSION_FOURTH */ - - /* Same as '_libiconv_version' if built with HAVE_ICONV */ - int iconv_ver_num; - - const char *libssh_version; /* human readable string */ - -} curl_version_info_data; - -#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ -#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ -#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ -#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ -#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ -#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */ -#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ -#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ -#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */ -#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ -#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ -#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ -#define CURL_VERSION_CONV (1<<12) /* character conversions are - supported */ - -/* - * NAME curl_version_info() - * - * DESCRIPTION - * - * This function returns a pointer to a static copy of the version info - * struct. See above. - */ -CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); - -/* - * NAME curl_easy_strerror() - * - * DESCRIPTION - * - * The curl_easy_strerror function may be used to turn a CURLcode value - * into the equivalent human readable error string. This is useful - * for printing meaningful error messages. - */ -CURL_EXTERN const char *curl_easy_strerror(CURLcode); - -/* - * NAME curl_share_strerror() - * - * DESCRIPTION - * - * The curl_share_strerror function may be used to turn a CURLSHcode value - * into the equivalent human readable error string. This is useful - * for printing meaningful error messages. - */ -CURL_EXTERN const char *curl_share_strerror(CURLSHcode); - -#ifdef __cplusplus -} -#endif - -/* unfortunately, the easy.h and multi.h include files need options and info - stuff before they can be included! */ -#include "easy.h" /* nothing in curl is fun without the easy stuff */ -#include "multi.h" - -#endif /* __CURL_CURL_H */ diff --git a/Utilities/cmcurl/curl/curlver.h b/Utilities/cmcurl/curl/curlver.h deleted file mode 100644 index 9380022..0000000 --- a/Utilities/cmcurl/curl/curlver.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __CURL_CURLVER_H -#define __CURL_CURLVER_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* This header file contains nothing but libcurl version info, generated by - a script at release-time. This was made its own header file in 7.11.2 */ - -/* This is the version number of the libcurl package from which this header - file origins: */ -#define LIBCURL_VERSION "7.16.1" - -/* The numeric version number is also available "in parts" by using these - defines: */ -#define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 16 -#define LIBCURL_VERSION_PATCH 1 - -/* This is the numeric version of the libcurl version number, meant for easier - parsing and comparions by programs. The LIBCURL_VERSION_NUM define will - always follow this syntax: - - 0xXXYYZZ - - 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 - appears as "0x090b07". - - This 6-digit (24 bits) hexadecimal number does not show pre-release number, - and it is always a greater number in a more recent release. It makes - comparisons with greater than and less than work. -*/ -#define LIBCURL_VERSION_NUM 0x071001 - -#endif /* __CURL_CURLVER_H */ diff --git a/Utilities/cmcurl/curl/easy.h b/Utilities/cmcurl/curl/easy.h deleted file mode 100644 index 17de210..0000000 --- a/Utilities/cmcurl/curl/easy.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef __CURL_EASY_H -#define __CURL_EASY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif - -CURL_EXTERN CURL *curl_easy_init(void); -CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); -CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); -CURL_EXTERN void curl_easy_cleanup(CURL *curl); - -/* - * NAME curl_easy_getinfo() - * - * DESCRIPTION - * - * Request internal information from the curl session with this function. The - * third argument MUST be a pointer to a long, a pointer to a char * or a - * pointer to a double (as the documentation describes elsewhere). 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 is completed. - */ -CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); - - -/* - * NAME curl_easy_duphandle() - * - * DESCRIPTION - * - * Creates a new curl session handle with the same options set for the handle - * passed in. Duplicating a handle could only be a matter of cloning data and - * options, internal state info and things like persistant connections cannot - * be transfered. It is useful in multithreaded applications when you can run - * curl_easy_duphandle() for each new thread to avoid a series of identical - * curl_easy_setopt() invokes in every thread. - */ -CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); - -/* - * NAME curl_easy_reset() - * - * DESCRIPTION - * - * Re-initializes a CURL handle to the default values. This puts back the - * handle to the same state as it was in when it was just created. - * - * It does keep: live connections, the Session ID cache, the DNS cache and the - * cookies. - */ -CURL_EXTERN void curl_easy_reset(CURL *curl); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Utilities/cmcurl/curl/mprintf.h b/Utilities/cmcurl/curl/mprintf.h deleted file mode 100644 index 5c52688..0000000 --- a/Utilities/cmcurl/curl/mprintf.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __CURL_MPRINTF_H -#define __CURL_MPRINTF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include -#include /* needed for FILE */ - -#include "curl.h" - -#ifdef __cplusplus -extern "C" { -#endif - -CURL_EXTERN int curl_mprintf(const char *format, ...); -CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); -CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); -CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...); -CURL_EXTERN int curl_mvprintf(const char *format, va_list args); -CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); -CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); -CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args); -CURL_EXTERN char *curl_maprintf(const char *format, ...); -CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); - -#ifdef _MPRINTF_REPLACE -# undef printf -# undef fprintf -# undef sprintf -# undef vsprintf -# undef snprintf -# undef vprintf -# undef vfprintf -# undef vsnprintf -# undef aprintf -# undef vaprintf -# define printf curl_mprintf -# define fprintf curl_mfprintf -#ifdef CURLDEBUG -/* When built with CURLDEBUG we define away the sprintf() functions since we - don't want internal code to be using them */ -# define sprintf sprintf_was_used -# define vsprintf vsprintf_was_used -#else -# define sprintf curl_msprintf -# define vsprintf curl_mvsprintf -#endif -# define snprintf curl_msnprintf -# define vprintf curl_mvprintf -# define vfprintf curl_mvfprintf -# define vsnprintf curl_mvsnprintf -# define aprintf curl_maprintf -# define vaprintf curl_mvaprintf -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __CURL_MPRINTF_H */ diff --git a/Utilities/cmcurl/curl/multi.h b/Utilities/cmcurl/curl/multi.h deleted file mode 100644 index 1b66747..0000000 --- a/Utilities/cmcurl/curl/multi.h +++ /dev/null @@ -1,327 +0,0 @@ -#ifndef __CURL_MULTI_H -#define __CURL_MULTI_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -/* - This is an "external" header file. Don't give away any internals here! - - GOALS - - o Enable a "pull" interface. The application that uses libcurl decides where - and when to ask libcurl to get/send data. - - o Enable multiple simultaneous transfers in the same thread without making it - complicated for the application. - - o Enable the application to select() on its own file descriptors and curl's - file descriptors simultaneous easily. - -*/ - -/* - * This header file should not really need to include "curl.h" since curl.h - * itself includes this file and we expect user applications to do #include - * without the need for especially including multi.h. - * - * For some reason we added this include here at one point, and rather than to - * break existing (wrongly written) libcurl applications, we leave it as-is - * but with this warning attached. - */ -#include "curl.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void CURLM; - -typedef enum { - CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or - curl_multi_socket*() soon */ - 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'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 */ - CURLM_LAST -} CURLMcode; - -/* just to make code nicer when using curl_multi_socket() you can now check - for CURLM_CALL_MULTI_SOCKET too in the same style it works for - curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ -#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM - -typedef enum { - CURLMSG_NONE, /* first, not used */ - CURLMSG_DONE, /* This easy handle has completed. 'result' contains - the CURLcode of the transfer */ - CURLMSG_LAST /* last, not used */ -} CURLMSG; - -struct CURLMsg { - CURLMSG msg; /* what this message means */ - CURL *easy_handle; /* the handle it concerns */ - union { - void *whatever; /* message-specific data */ - CURLcode result; /* return code for transfer */ - } data; -}; -typedef struct CURLMsg CURLMsg; - -/* - * Name: curl_multi_init() - * - * Desc: inititalize multi-style curl usage - * - * Returns: a new CURLM handle to use in all 'curl_multi' functions. - */ -CURL_EXTERN CURLM *curl_multi_init(void); - -/* - * Name: curl_multi_add_handle() - * - * Desc: add a standard curl handle to the multi stack - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, - CURL *curl_handle); - - /* - * Name: curl_multi_remove_handle() - * - * Desc: removes a curl handle from the multi stack again - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, - CURL *curl_handle); - - /* - * Name: curl_multi_fdset() - * - * Desc: Ask curl for its fd_set sets. The app can use these to select() or - * poll() on. We want curl_multi_perform() called as soon as one of - * them are ready. - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, - fd_set *read_fd_set, - fd_set *write_fd_set, - fd_set *exc_fd_set, - int *max_fd); - - /* - * Name: curl_multi_perform() - * - * 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 - * data can be written, it can be called just in case. It returns - * the number of handles that still transfer data in the second - * argument's integer-pointer. - * - * Returns: CURLMcode type, general multi error code. *NOTE* that this only - * returns errors etc regarding the whole multi stack. There might - * still have occurred problems on invidual transfers even when this - * returns OK. - */ -CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, - int *running_handles); - - /* - * Name: curl_multi_cleanup() - * - * Desc: Cleans up and removes a whole multi stack. It does not free or - * touch any individual easy handles in any way. We need to define - * in what state those handles will be if this function is called - * in the middle of a transfer. - * - * Returns: CURLMcode type, general multi error code. - */ -CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); - -/* - * Name: curl_multi_info_read() - * - * 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. - * - * Repeated calls to this function will return a new struct each - * time, until a special "end of msgs" struct is returned as a signal - * that there is no more to get at this point. - * - * The data the returned pointer points to will not survive calling - * curl_multi_cleanup(). - * - * The 'CURLMsg' struct is meant to be very simple and only contain - * very basic information. If more involved information is wanted, - * 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'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 - * of structs. It also writes the number of messages left in the - * queue (after this read) in the integer the second argument points - * to. - */ -CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, - int *msgs_in_queue); - -/* - * 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 - * useful for printing meaningful error messages. - * - * Returns: A pointer to a zero-terminated error message. - */ -CURL_EXTERN const char *curl_multi_strerror(CURLMcode); - -/* - * Name: curl_multi_socket() and - * curl_multi_socket_all() - * - * 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 man page for details. - */ -#define CURL_POLL_NONE 0 -#define CURL_POLL_IN 1 -#define CURL_POLL_OUT 2 -#define CURL_POLL_INOUT 3 -#define CURL_POLL_REMOVE 4 - -#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD - -typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ - curl_socket_t s, /* socket */ - int what, /* see above */ - void *userp, /* private callback - pointer */ - void *socketp); /* private socket - pointer */ -/* - * Name: curl_multi_timer_callback - * - * Desc: Called by libcurl whenever the library detects a change in the - * maximum number of milliseconds the app is allowed to wait before - * curl_multi_socket() or curl_multi_perform() must be called - * (to allow libcurl's timed events to take place). - * - * Returns: The callback should return zero. - */ -typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ - long timeout_ms, /* see above */ - void *userp); /* private callback - pointer */ - -CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, - int *running_handles); - -CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, - int *running_handles); - -/* - * Name: curl_multi_timeout() - * - * Desc: Returns the maximum number of milliseconds the app is allowed to - * wait before curl_multi_socket() or curl_multi_perform() must be - * called (to allow libcurl's timed events to take place). - * - * Returns: CURLM error code. - */ -CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, - long *milliseconds); - -#undef CINIT /* re-using the same name as in curl.h */ - -#ifdef CURL_ISOCPP -#define CINIT(name,type,number) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + number -#else -/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ -#define LONG CURLOPTTYPE_LONG -#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT -#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT -#define OFF_T CURLOPTTYPE_OFF_T -#define CINIT(name,type,number) CURLMOPT_/**/name = type + number -#endif - -typedef enum { - /* This is the socket callback function pointer */ - CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), - - /* This is the argument passed to the socket callback */ - CINIT(SOCKETDATA, OBJECTPOINT, 2), - - /* set to 1 to enable pipelining for this multi handle */ - CINIT(PIPELINING, LONG, 3), - - /* This is the timer callback function pointer */ - CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), - - /* This is the argument passed to the timer callback */ - CINIT(TIMERDATA, OBJECTPOINT, 5), - - CURLMOPT_LASTENTRY /* the last unused */ -} CURLMoption; - - -/* - * Name: curl_multi_setopt() - * - * Desc: Sets options for the multi handle. - * - * Returns: CURLM error code. - */ -CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, - CURLMoption option, ...); - - -/* - * Name: curl_multi_assign() - * - * Desc: This function sets an association in the multi handle between the - * given socket and a private pointer of the application. This is - * (only) useful for curl_multi_socket uses. - * - * Returns: CURLM error code. - */ -CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, - curl_socket_t sockfd, void *sockp); - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif diff --git a/Utilities/cmcurl/curl/stdcheaders.h b/Utilities/cmcurl/curl/stdcheaders.h deleted file mode 100644 index 11c1e2f..0000000 --- a/Utilities/cmcurl/curl/stdcheaders.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __STDC_HEADERS_H -#define __STDC_HEADERS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include - -size_t fread (void *, size_t, size_t, FILE *); -size_t fwrite (const void *, size_t, size_t, FILE *); - -int strcasecmp(const char *, const char *); -int strncasecmp(const char *, const char *, size_t); - -#endif diff --git a/Utilities/cmcurl/curl/types.h b/Utilities/cmcurl/curl/types.h deleted file mode 100644 index d37d6ae..0000000 --- a/Utilities/cmcurl/curl/types.h +++ /dev/null @@ -1 +0,0 @@ -/* not used */ diff --git a/Utilities/cmcurl/curlx.h b/Utilities/cmcurl/curlx.h deleted file mode 100644 index 26948d3..0000000 --- a/Utilities/cmcurl/curlx.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef __CURLX_H -#define __CURLX_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * Defines protos and includes all header files that provide the curlx_* - * functions. The curlx_* functions are not part of the libcurl API, but are - * stand-alone functions whose sources can be built and linked by apps if need - * be. - */ - -#include -/* 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 "strequal.h" -/* "strequal.h" provides the strequal protos */ - -#include "strtoofft.h" -/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a - curl_off_t number from a given string. -*/ - -#include "timeval.h" -/* - "timeval.h" sets up a 'struct timeval' even for platforms that otherwise - don't have one and has protos for these functions: - - curlx_tvnow() - curlx_tvdiff() - curlx_tvdiff_secs() -*/ - -/* Now setup curlx_ * names for the functions that are to become curlx_ and - be removed from a future libcurl official API: - curlx_getenv - curlx_mprintf (and its variations) - curlx_strequal - curlx_strnequal - -*/ - -#define curlx_getenv curl_getenv -#define curlx_strequal curl_strequal -#define curlx_strnequal curl_strnequal -#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 transparant and - easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE - is set. */ -# undef printf -# undef fprintf -# undef sprintf -# undef snprintf -# undef vprintf -# undef vfprintf -# undef vsprintf -# undef vsnprintf -# undef aprintf -# undef vaprintf - -# define printf curlx_mprintf -# define fprintf curlx_mfprintf -# define sprintf curlx_msprintf -# define snprintf curlx_msnprintf -# define vprintf curlx_mvprintf -# define vfprintf curlx_mvfprintf -# define vsprintf curlx_mvsprintf -# define vsnprintf curlx_mvsnprintf -# define aprintf curlx_maprintf -# define vaprintf curlx_mvaprintf -#endif /* ENABLE_CURLX_PRINTF */ - -#endif /* __CURLX_H */ diff --git a/Utilities/cmcurl/dict.c b/Utilities/cmcurl/dict.c deleted file mode 100644 index d6443f4..0000000 --- a/Utilities/cmcurl/dict.c +++ /dev/null @@ -1,280 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_DICT - -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - - -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" - -#include "progress.h" -#include "strequal.h" -#include "dict.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -static char *unescape_word(struct SessionHandle *data, char *inp) -{ - char *newp; - char *dictp; - char *ptr; - int len; - unsigned char byte; - int olen=0; - - newp = curl_easy_unescape(data, inp, 0, &len); - if(!newp) - return NULL; - - dictp = malloc(len*2 + 1); /* add one for terminating zero */ - if(dictp) { - /* According to RFC2229 section 2.2, these letters need to be escaped with - \[letter] */ - for(ptr = newp; - (byte = (unsigned char)*ptr) != 0; - ptr++) { - if ((byte <= 32) || (byte == 127) || - (byte == '\'') || (byte == '\"') || (byte == '\\')) { - dictp[olen++] = '\\'; - } - dictp[olen++] = byte; - } - dictp[olen]=0; - - free(newp); - } - return dictp; -} - -CURLcode Curl_dict(struct connectdata *conn, bool *done) -{ - char *word; - char *eword; - char *ppath; - char *database = NULL; - char *strategy = NULL; - char *nthdef = NULL; /* This is not part of the protocol, but required - by RFC 2229 */ - CURLcode result=CURLE_OK; - struct SessionHandle *data=conn->data; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - - char *path = data->reqdata.path; - curl_off_t *bytecount = &data->reqdata.keep.bytecount; - - *done = TRUE; /* unconditionally */ - - if(conn->bits.user_passwd) { - /* AUTH is missing */ - } - - if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || - strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || - strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { - - word = strchr(path, ':'); - if (word) { - word++; - database = strchr(word, ':'); - if (database) { - *database++ = (char)0; - strategy = strchr(database, ':'); - if (strategy) { - *strategy++ = (char)0; - nthdef = strchr(strategy, ':'); - if (nthdef) { - *nthdef++ = (char)0; - } - } - } - } - - if ((word == NULL) || (*word == (char)0)) { - failf(data, "lookup word is missing"); - } - if ((database == NULL) || (*database == (char)0)) { - database = (char *)"!"; - } - if ((strategy == NULL) || (*strategy == (char)0)) { - strategy = (char *)"."; - } - - eword = unescape_word(data, word); - if(!eword) - return CURLE_OUT_OF_MEMORY; - - result = Curl_sendf(sockfd, conn, - "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" - "MATCH " - "%s " /* database */ - "%s " /* strategy */ - "%s\r\n" /* word */ - "QUIT\r\n", - - database, - strategy, - eword - ); - - free(eword); - - if(result) - failf(data, "Failed sending DICT request"); - else - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, - -1, NULL); /* no upload */ - if(result) - return result; - } - else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || - strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || - strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { - - word = strchr(path, ':'); - if (word) { - word++; - database = strchr(word, ':'); - if (database) { - *database++ = (char)0; - nthdef = strchr(database, ':'); - if (nthdef) { - *nthdef++ = (char)0; - } - } - } - - if ((word == NULL) || (*word == (char)0)) { - failf(data, "lookup word is missing"); - } - if ((database == NULL) || (*database == (char)0)) { - database = (char *)"!"; - } - - eword = unescape_word(data, word); - if(!eword) - return CURLE_OUT_OF_MEMORY; - - result = Curl_sendf(sockfd, conn, - "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" - "DEFINE " - "%s " /* database */ - "%s\r\n" /* word */ - "QUIT\r\n", - database, - eword); - - free(eword); - - if(result) - failf(data, "Failed sending DICT request"); - else - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, - -1, NULL); /* no upload */ - - if(result) - return result; - - } - else { - - ppath = strchr(path, '/'); - if (ppath) { - int i; - - ppath++; - for (i = 0; ppath[i]; i++) { - if (ppath[i] == ':') - ppath[i] = ' '; - } - result = Curl_sendf(sockfd, conn, - "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" - "%s\r\n" - "QUIT\r\n", ppath); - if(result) - failf(data, "Failed sending DICT request"); - else - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, - -1, NULL); - if(result) - return result; - } - } - - return CURLE_OK; -} -#endif /*CURL_DISABLE_DICT*/ diff --git a/Utilities/cmcurl/dict.h b/Utilities/cmcurl/dict.h deleted file mode 100644 index d3da193..0000000 --- a/Utilities/cmcurl/dict.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __DICT_H -#define __DICT_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_DICT -CURLcode Curl_dict(struct connectdata *conn, bool *done); -CURLcode Curl_dict_done(struct connectdata *conn); -#endif -#endif diff --git a/Utilities/cmcurl/easy.c b/Utilities/cmcurl/easy.c deleted file mode 100644 index 209d1c3..0000000 --- a/Utilities/cmcurl/easy.c +++ /dev/null @@ -1,895 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#include - -#include "strequal.h" - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#endif /* WIN32 ... */ - -#include "urldata.h" -#include -#include "transfer.h" -#include "sslgen.h" -#include "url.h" -#include "getinfo.h" -#include "hostip.h" -#include "share.h" -#include "strdup.h" -#include "memory.h" -#include "progress.h" -#include "easyif.h" -#include "sendf.h" /* for failf function prototype */ -#include - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) -#include -/* set default codesets for iconv */ -#ifndef CURL_ICONV_CODESET_OF_NETWORK -#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" -#endif -#ifndef CURL_ICONV_CODESET_FOR_UTF8 -#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" -#endif -#define ICONV_ERROR (size_t)-1 -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifdef USE_WINSOCK -/* win32_cleanup() is for win32 socket cleanup functionality, the opposite - of win32_init() */ -static void win32_cleanup(void) -{ - WSACleanup(); -} - -/* win32_init() performs win32 socket initialization to properly setup the - stack to allow networking */ -static CURLcode win32_init(void) -{ - WORD wVersionRequested; - WSADATA wsaData; - int err; - -#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2) - Error IPV6_requires_winsock2 -#endif - - wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); - - err = WSAStartup(wVersionRequested, &wsaData); - - if (err != 0) - /* Tell the user that we couldn't find a useable */ - /* winsock.dll. */ - return CURLE_FAILED_INIT; - - /* Confirm that the Windows Sockets DLL supports what we need.*/ - /* Note that if the DLL supports versions greater */ - /* than wVersionRequested, it will still return */ - /* wVersionRequested in wVersion. wHighVersion contains the */ - /* highest supported version. */ - - if ( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || - HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { - /* Tell the user that we couldn't find a useable */ - - /* winsock.dll. */ - WSACleanup(); - return CURLE_FAILED_INIT; - } - /* The Windows Sockets DLL is acceptable. Proceed. */ - return CURLE_OK; -} - -#else -/* These functions exist merely to prevent compiler warnings */ -static CURLcode win32_init(void) { return CURLE_OK; } -static void win32_cleanup(void) { } -#endif - -#ifdef USE_LIBIDN -/* - * Initialise use of IDNA library. - * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for - * idna_to_ascii_lz(). - */ -static void idna_init (void) -{ -#ifdef WIN32 - char buf[60]; - UINT cp = GetACP(); - - if (!getenv("CHARSET") && cp > 0) { - snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp); - putenv(buf); - } -#else - /* to do? */ -#endif -} -#endif /* USE_LIBIDN */ - -/* true globals -- for curl_global_init() and curl_global_cleanup() */ -static unsigned int initialized; -static long init_flags; - -/* - * strdup (and other memory functions) is redefined in complicated - * ways, but at this point it must be defined as the system-supplied strdup - * so the callback pointer is initialized correctly. - */ -#if defined(_WIN32_WCE) -#define system_strdup _strdup -#elif !defined(HAVE_STRDUP) -#define system_strdup curlx_strdup -#else -#define system_strdup strdup -#endif - -/* - * If a memory-using function (like curl_getenv) is used before - * curl_global_init() is called, we need to have these pointers set already. - */ - -curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; -curl_free_callback Curl_cfree = (curl_free_callback)free; -curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; -curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; -curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; - -/** - * curl_global_init() globally initializes cURL given a bitwise set of the - * different features of what to initialize. - */ -CURLcode curl_global_init(long flags) -{ - if (initialized++) - return CURLE_OK; - - /* Setup the default memory functions here (again) */ - Curl_cmalloc = (curl_malloc_callback)malloc; - Curl_cfree = (curl_free_callback)free; - Curl_crealloc = (curl_realloc_callback)realloc; - Curl_cstrdup = (curl_strdup_callback)system_strdup; - Curl_ccalloc = (curl_calloc_callback)calloc; - - if (flags & CURL_GLOBAL_SSL) - if (!Curl_ssl_init()) - return CURLE_FAILED_INIT; - - if (flags & CURL_GLOBAL_WIN32) - if (win32_init() != CURLE_OK) - return CURLE_FAILED_INIT; - -#ifdef _AMIGASF - if(!amiga_init()) - return CURLE_FAILED_INIT; -#endif - -#ifdef USE_LIBIDN - idna_init(); -#endif - - init_flags = flags; - - return CURLE_OK; -} - -/* - * curl_global_init_mem() globally initializes cURL and also registers the - * user provided callback routines. - */ -CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, - curl_free_callback f, curl_realloc_callback r, - curl_strdup_callback s, curl_calloc_callback c) -{ - CURLcode code = CURLE_OK; - - /* Invalid input, return immediately */ - if (!m || !f || !r || !s || !c) - return CURLE_FAILED_INIT; - - /* Already initialized, don't do it again */ - if ( initialized ) - return CURLE_OK; - - /* Call the actual init function first */ - code = curl_global_init(flags); - if (code == CURLE_OK) { - Curl_cmalloc = m; - Curl_cfree = f; - Curl_cstrdup = s; - Curl_crealloc = r; - Curl_ccalloc = c; - } - - return code; -} - -/** - * curl_global_cleanup() globally cleanups cURL, uses the value of - * "init_flags" to determine what needs to be cleaned up and what doesn't. - */ -void curl_global_cleanup(void) -{ - if (!initialized) - return; - - if (--initialized) - return; - - Curl_global_host_cache_dtor(); - - if (init_flags & CURL_GLOBAL_SSL) - Curl_ssl_cleanup(); - - if (init_flags & CURL_GLOBAL_WIN32) - win32_cleanup(); - -#ifdef _AMIGASF - amiga_cleanup(); -#endif - - init_flags = 0; -} - -/* - * curl_easy_init() is the external interface to alloc, setup and init an - * easy handle that is returned. If anything goes wrong, NULL is returned. - */ -CURL *curl_easy_init(void) -{ - CURLcode res; - struct SessionHandle *data; - - /* Make sure we inited the global SSL stuff */ - if (!initialized) { - res = curl_global_init(CURL_GLOBAL_DEFAULT); - if(res) - /* something in the global init failed, return nothing */ - return NULL; - } - - /* We use curl_open() with undefined URL so far */ - res = Curl_open(&data); - if(res != CURLE_OK) - return NULL; - - return data; -} - -/* - * curl_easy_setopt() is the external interface for setting options on an - * easy handle. - */ - -CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) -{ - va_list arg; - struct SessionHandle *data = curl; - CURLcode ret; - - if(!curl) - return CURLE_BAD_FUNCTION_ARGUMENT; - - va_start(arg, tag); - - ret = Curl_setopt(data, tag, arg); - - va_end(arg); - return ret; -} - -#ifdef CURL_MULTIEASY -/*************************************************************************** - * This function is still only for testing purposes. It makes a great way - * to run the full test suite on the multi interface instead of the easy one. - *************************************************************************** - * - * The *new* curl_easy_perform() is the external interface that performs a - * transfer previously setup. - * - * Wrapper-function that: creates a multi handle, adds the easy handle to it, - * runs curl_multi_perform() until the transfer is done, then detaches the - * easy handle, destroys the multi handle and returns the easy handle's return - * code. This will make everything internally use and assume multi interface. - */ -CURLcode curl_easy_perform(CURL *easy) -{ - CURLM *multi; - CURLMcode mcode; - CURLcode code = CURLE_OK; - int still_running; - struct timeval timeout; - int rc; - CURLMsg *msg; - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd; - - if(!easy) - return CURLE_BAD_FUNCTION_ARGUMENT; - - multi = curl_multi_init(); - if(!multi) - return CURLE_OUT_OF_MEMORY; - - mcode = curl_multi_add_handle(multi, easy); - if(mcode) { - curl_multi_cleanup(multi); - return CURLE_FAILED_INIT; - } - - /* we start some action by calling perform right away */ - - do { - while(CURLM_CALL_MULTI_PERFORM == - curl_multi_perform(multi, &still_running)); - - if(!still_running) - break; - - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); - - /* timeout once per second */ - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - /* get file descriptors from the transfers */ - curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); - - rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - - if(rc == -1) - /* select error */ - break; - - /* timeout or data to send/receive => loop! */ - } while(still_running); - - msg = curl_multi_info_read(multi, &rc); - if(msg) - code = msg->data.result; - - mcode = curl_multi_remove_handle(multi, easy); - /* what to do if it fails? */ - - mcode = curl_multi_cleanup(multi); - /* what to do if it fails? */ - - return code; -} -#else -/* - * curl_easy_perform() is the external interface that performs a transfer - * previously setup. - */ -CURLcode curl_easy_perform(CURL *curl) -{ - struct SessionHandle *data = (struct SessionHandle *)curl; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - if ( ! (data->share && data->share->hostcache) ) { - - if (Curl_global_host_cache_use(data) && - (data->dns.hostcachetype != HCACHE_GLOBAL)) { - if (data->dns.hostcachetype == HCACHE_PRIVATE) - Curl_hash_destroy(data->dns.hostcache); - data->dns.hostcache = Curl_global_host_cache_get(); - data->dns.hostcachetype = HCACHE_GLOBAL; - } - - if (!data->dns.hostcache) { - data->dns.hostcachetype = HCACHE_PRIVATE; - data->dns.hostcache = Curl_mk_dnscache(); - - if(!data->dns.hostcache) - /* While we possibly could survive and do good without a host cache, - the fact that creating it failed indicates that things are truly - screwed up and we should bail out! */ - return CURLE_OUT_OF_MEMORY; - } - - } - - if(!data->state.connc) { - /* oops, no connection cache, make one up */ - data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1); - if(!data->state.connc) - return CURLE_OUT_OF_MEMORY; - } - - return Curl_perform(data); -} -#endif - -/* - * curl_easy_cleanup() is the external interface to cleaning/freeing the given - * easy handle. - */ -void curl_easy_cleanup(CURL *curl) -{ - struct SessionHandle *data = (struct SessionHandle *)curl; - - if(!data) - return; - - Curl_close(data); -} - -/* - * Store a pointed to the multi handle within the easy handle's data struct. - */ -void Curl_easy_addmulti(struct SessionHandle *data, - void *multi) -{ - data->multi = multi; -} - -void Curl_easy_initHandleData(struct SessionHandle *data) -{ - memset(&data->reqdata, 0, sizeof(struct HandleData)); - - data->reqdata.maxdownload = -1; -} - -/* - * curl_easy_getinfo() is an external interface that allows an app to retrieve - * information from a performed transfer and similar. - */ -CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) -{ - va_list arg; - void *paramp; - struct SessionHandle *data = (struct SessionHandle *)curl; - - va_start(arg, info); - paramp = va_arg(arg, void *); - - return Curl_getinfo(data, info, paramp); -} - -/* - * curl_easy_duphandle() is an external interface to allow duplication of a - * given input easy handle. The returned handle will be a new working handle - * with all options set exactly as the input source handle. - */ -CURL *curl_easy_duphandle(CURL *incurl) -{ - bool fail = TRUE; - struct SessionHandle *data=(struct SessionHandle *)incurl; - - struct SessionHandle *outcurl = (struct SessionHandle *) - calloc(sizeof(struct SessionHandle), 1); - - if(NULL == outcurl) - return NULL; /* failure */ - - do { - - /* - * We setup a few buffers we need. We should probably make them - * get setup on-demand in the code, as that would probably decrease - * the likeliness of us forgetting to init a buffer here in the future. - */ - outcurl->state.headerbuff=(char*)malloc(HEADERSIZE); - if(!outcurl->state.headerbuff) { - break; - } - outcurl->state.headersize=HEADERSIZE; - - /* copy all userdefined values */ - outcurl->set = data->set; - - if(data->state.used_interface == Curl_if_multi) - outcurl->state.connc = data->state.connc; - else - outcurl->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1); - - if(!outcurl->state.connc) - break; - - outcurl->state.lastconnect = -1; - - outcurl->progress.flags = data->progress.flags; - outcurl->progress.callback = data->progress.callback; - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(data->cookies) { - /* If cookies are enabled in the parent handle, we enable them - in the clone as well! */ - outcurl->cookies = Curl_cookie_init(data, - data->cookies->filename, - outcurl->cookies, - data->set.cookiesession); - if(!outcurl->cookies) { - break; - } - } -#endif /* CURL_DISABLE_HTTP */ - - /* duplicate all values in 'change' */ - - if(data->change.url) { - outcurl->change.url = strdup(data->change.url); - if(!outcurl->change.url) - break; - outcurl->change.url_alloc = TRUE; - } - - if(data->change.referer) { - outcurl->change.referer = strdup(data->change.referer); - if(!outcurl->change.referer) - break; - outcurl->change.referer_alloc = TRUE; - } - -#ifdef USE_ARES - /* If we use ares, we setup a new ares channel for the new handle */ - if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel)) - break; -#endif - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); -#endif - - Curl_easy_initHandleData(outcurl); - - outcurl->magic = CURLEASY_MAGIC_NUMBER; - - fail = FALSE; /* we reach this point and thus we are OK */ - - } while(0); - - if(fail) { - if(outcurl) { - if(outcurl->state.connc->type == CONNCACHE_PRIVATE) - Curl_rm_connc(outcurl->state.connc); - if(outcurl->state.headerbuff) - free(outcurl->state.headerbuff); - if(outcurl->change.url) - free(outcurl->change.url); - if(outcurl->change.referer) - free(outcurl->change.referer); - free(outcurl); /* free the memory again */ - outcurl = NULL; - } - } - - return outcurl; -} - -/* - * curl_easy_reset() is an external interface that allows an app to re- - * initialize a session handle to the default values. - */ -void curl_easy_reset(CURL *curl) -{ - struct SessionHandle *data = (struct SessionHandle *)curl; - - Curl_safefree(data->reqdata.pathbuffer); - data->reqdata.pathbuffer=NULL; - - Curl_safefree(data->reqdata.proto.generic); - data->reqdata.proto.generic=NULL; - - /* zero out UserDefined data: */ - memset(&data->set, 0, sizeof(struct UserDefined)); - - /* zero out Progress data: */ - memset(&data->progress, 0, sizeof(struct Progress)); - - /* init Handle data */ - Curl_easy_initHandleData(data); - - /* The remainder of these calls have been taken from Curl_open() */ - - data->set.out = stdout; /* default output to stdout */ - data->set.in = stdin; /* default input from stdin */ - data->set.err = stderr; /* default stderr to stderr */ - - /* use fwrite as default function to store output */ - data->set.fwrite = (curl_write_callback)fwrite; - - /* use fread as default function to read input */ - data->set.fread = (curl_read_callback)fread; - - data->set.infilesize = -1; /* we don't know any size */ - data->set.postfieldsize = -1; - - data->state.current_speed = -1; /* init to negative == impossible */ - - data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */ - data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ - data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ - - data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ - - /* make libcurl quiet by default: */ - data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ - data->progress.flags |= PGRS_HIDE; - - /* Set the default size of the SSL session ID cache */ - data->set.ssl.numsessions = 5; - - data->set.proxyport = 1080; - data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ - data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */ - data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */ - - /* - * libcurl 7.10 introduced SSL verification *by default*! This needs to be - * switched off unless wanted. - */ - data->set.ssl.verifypeer = TRUE; - data->set.ssl.verifyhost = 2; -#ifdef CURL_CA_BUNDLE - /* This is our preferred CA cert bundle since install time */ - data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; -#endif - - data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth - type */ -} - -#ifdef CURL_DOES_CONVERSIONS -/* - * Curl_convert_to_network() is an internal function - * for performing ASCII conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_to_network(struct SessionHandle *data, - char *buffer, size_t length) -{ - CURLcode rc; - - if(data->set.convtonetwork) { - /* use translation callback */ - rc = data->set.convtonetwork(buffer, length); - if(rc != CURLE_OK) { - failf(data, - "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s", - rc, curl_easy_strerror(rc)); - } - return(rc); - } else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - - /* open an iconv conversion descriptor if necessary */ - if(data->outbound_cd == (iconv_t)-1) { - data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - if(data->outbound_cd == (iconv_t)-1) { - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST, - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if ((rc == ICONV_ERROR) || (in_bytes != 0)) { - failf(data, - "The Curl_convert_to_network iconv call failed with errno %i: %s", - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } -#else - failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Curl_convert_from_network() is an internal function - * for performing ASCII conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_from_network(struct SessionHandle *data, - char *buffer, size_t length) -{ - CURLcode rc; - - if(data->set.convfromnetwork) { - /* use translation callback */ - rc = data->set.convfromnetwork(buffer, length); - if(rc != CURLE_OK) { - failf(data, - "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s", - rc, curl_easy_strerror(rc)); - } - return(rc); - } else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - - /* open an iconv conversion descriptor if necessary */ - if(data->inbound_cd == (iconv_t)-1) { - data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - if(data->inbound_cd == (iconv_t)-1) { - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK, - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if ((rc == ICONV_ERROR) || (in_bytes != 0)) { - failf(data, - "The Curl_convert_from_network iconv call failed with errno %i: %s", - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } -#else - failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Curl_convert_from_utf8() is an internal function - * for performing UTF-8 conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, - char *buffer, size_t length) -{ - CURLcode rc; - - if(data->set.convfromutf8) { - /* use translation callback */ - rc = data->set.convfromutf8(buffer, length); - if(rc != CURLE_OK) { - failf(data, - "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s", - rc, curl_easy_strerror(rc)); - } - return(rc); - } else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - - /* open an iconv conversion descriptor if necessary */ - if(data->utf8_cd == (iconv_t)-1) { - data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); - if(data->utf8_cd == (iconv_t)-1) { - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8, - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(data->utf8_cd, (const char**)&input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if ((rc == ICONV_ERROR) || (in_bytes != 0)) { - failf(data, - "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", - errno, strerror(errno)); - return CURLE_CONV_FAILED; - } - if (output_ptr < input_ptr) { - /* null terminate the now shorter output string */ - *output_ptr = 0x00; - } -#else - failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -#endif /* CURL_DOES_CONVERSIONS */ diff --git a/Utilities/cmcurl/easyif.h b/Utilities/cmcurl/easyif.h deleted file mode 100644 index 4c0f7e7..0000000 --- a/Utilities/cmcurl/easyif.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __EASYIF_H -#define __EASYIF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * Prototypes for library-wide functions provided by easy.c - */ -void Curl_easy_addmulti(struct SessionHandle *data, void *multi); - -void Curl_easy_initHandleData(struct SessionHandle *data); - -CURLcode Curl_convert_to_network(struct SessionHandle *data, - char *buffer, size_t length); -CURLcode Curl_convert_from_network(struct SessionHandle *data, - char *buffer, size_t length); -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, - char *buffer, size_t length); - -#endif /* __EASYIF_H */ diff --git a/Utilities/cmcurl/escape.c b/Utilities/cmcurl/escape.c deleted file mode 100644 index 9552b0f..0000000 --- a/Utilities/cmcurl/escape.c +++ /dev/null @@ -1,181 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* Escape and unescape URL encoding in strings. The functions return a new - * allocated string or NULL if an error occurred. */ - -#include "setup.h" -#include -#include - -#include -#include -#include -#include "memory.h" -/* urldata.h and easyif.h are included for Curl_convert_... prototypes */ -#include "urldata.h" -#include "easyif.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -/* for ABI-compatibility with previous versions */ -char *curl_escape(const char *string, int inlength) -{ - return curl_easy_escape(NULL, string, inlength); -} - -/* for ABI-compatibility with previous versions */ -char *curl_unescape(const char *string, int length) -{ - return curl_easy_unescape(NULL, string, length, NULL); -} - -char *curl_easy_escape(CURL *handle, const char *string, int inlength) -{ - size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; - char *ns; - char *testing_ptr = NULL; - unsigned char in; - size_t newlen = alloc; - int strindex=0; - size_t length; - -#ifndef CURL_DOES_CONVERSIONS - /* avoid compiler warnings */ - (void)handle; -#endif - ns = malloc(alloc); - if(!ns) - return NULL; - - length = alloc-1; - while(length--) { - in = *string; - if(!(in >= 'a' && in <= 'z') && - !(in >= 'A' && in <= 'Z') && - !(in >= '0' && in <= '9')) { - /* encode it */ - newlen += 2; /* the size grows with two, since this'll become a %XX */ - if(newlen > alloc) { - alloc *= 2; - testing_ptr = realloc(ns, alloc); - if(!testing_ptr) { - free( ns ); - return NULL; - } - else { - ns = testing_ptr; - } - } - -#ifdef CURL_DOES_CONVERSIONS -/* escape sequences are always in ASCII so convert them on non-ASCII hosts */ - if (!handle || - (Curl_convert_to_network(handle, &in, 1) != CURLE_OK)) { - /* Curl_convert_to_network calls failf if unsuccessful */ - free(ns); - return NULL; - } -#endif /* CURL_DOES_CONVERSIONS */ - - snprintf(&ns[strindex], 4, "%%%02X", in); - - strindex+=3; - } - else { - /* just copy this */ - ns[strindex++]=in; - } - string++; - } - ns[strindex]=0; /* terminate it */ - return ns; -} - -char *curl_easy_unescape(CURL *handle, const char *string, int length, - int *olen) -{ - int alloc = (length?length:(int)strlen(string))+1; - char *ns = malloc(alloc); - unsigned char in; - int strindex=0; - long hex; - -#ifndef CURL_DOES_CONVERSIONS - /* avoid compiler warnings */ - (void)handle; -#endif - if( !ns ) - return NULL; - - while(--alloc > 0) { - in = *string; - if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { - /* this is two hexadecimal digits following a '%' */ - char hexstr[3]; - char *ptr; - hexstr[0] = string[1]; - hexstr[1] = string[2]; - hexstr[2] = 0; - - hex = strtol(hexstr, &ptr, 16); - - in = (unsigned char)hex; /* this long is never bigger than 255 anyway */ - -#ifdef CURL_DOES_CONVERSIONS -/* escape sequences are always in ASCII so convert them on non-ASCII hosts */ - if (!handle || - (Curl_convert_from_network(handle, &in, 1) != CURLE_OK)) { - /* Curl_convert_from_network calls failf if unsuccessful */ - free(ns); - return NULL; - } -#endif /* CURL_DOES_CONVERSIONS */ - - string+=2; - alloc-=2; - } - - ns[strindex++] = in; - string++; - } - ns[strindex]=0; /* terminate it */ - - if(olen) - /* store output size */ - *olen = strindex; - return ns; -} - -/* For operating systems/environments that use different malloc/free - ssystems for the app and for this library, we provide a free that uses - the library's memory system */ -void curl_free(void *p) -{ - if(p) - free(p); -} diff --git a/Utilities/cmcurl/escape.h b/Utilities/cmcurl/escape.h deleted file mode 100644 index a0a0209..0000000 --- a/Utilities/cmcurl/escape.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __ESCAPE_H -#define __ESCAPE_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -/* Escape and unescape URL encoding in strings. The functions return a new - * allocated string or NULL if an error occurred. */ - - -#endif diff --git a/Utilities/cmcurl/file.c b/Utilities/cmcurl/file.c deleted file mode 100644 index b247a77..0000000 --- a/Utilities/cmcurl/file.c +++ /dev/null @@ -1,407 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_FILE -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#ifdef WIN32 -#include -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_FCNTL_H -#include -#endif - -#endif - -#include "urldata.h" -#include -#include "progress.h" -#include "sendf.h" -#include "escape.h" -#include "file.h" -#include "speedcheck.h" -#include "getinfo.h" -#include "transfer.h" -#include "url.h" -#include "memory.h" -#include "parsedate.h" /* for the week day and month names */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to - * do protocol-specific actions at connect-time. We emulate a - * connect-then-transfer protocol and "connect" to the file here - */ -CURLcode Curl_file_connect(struct connectdata *conn) -{ - char *real_path = curl_easy_unescape(conn->data, conn->data->reqdata.path, 0, NULL); - struct FILEPROTO *file; - int fd; -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) - int i; - char *actual_path; -#endif - - if(!real_path) - return CURLE_OUT_OF_MEMORY; - - file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1); - if(!file) { - free(real_path); - return CURLE_OUT_OF_MEMORY; - } - - if (conn->data->reqdata.proto.file) { - free(conn->data->reqdata.proto.file); - } - - conn->data->reqdata.proto.file = file; - -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) - /* 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 - slash in all cases, paths without drive letters end up - 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 - with a drive letter. - */ - actual_path = real_path; - if ((actual_path[0] == '/') && - actual_path[1] && - (actual_path[2] == ':' || actual_path[2] == '|')) - { - actual_path[2] = ':'; - actual_path++; - } - - /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for (i=0; actual_path[i] != '\0'; ++i) - if (actual_path[i] == '/') - actual_path[i] = '\\'; - - fd = open(actual_path, O_RDONLY | O_BINARY); /* no CR/LF translation! */ - file->path = actual_path; -#else - fd = open(real_path, O_RDONLY); - file->path = real_path; -#endif - file->freepath = real_path; /* free this when done */ - - file->fd = fd; - if(!conn->data->set.upload && (fd == -1)) { - failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path); - Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); - return CURLE_FILE_COULDNT_READ_FILE; - } - - return CURLE_OK; -} - -CURLcode Curl_file_done(struct connectdata *conn, - CURLcode status, bool premature) -{ - struct FILEPROTO *file = conn->data->reqdata.proto.file; - (void)status; /* not used */ - (void)premature; /* not used */ - Curl_safefree(file->freepath); - - if(file->fd != -1) - close(file->fd); - - return CURLE_OK; -} - -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) -#define DIRSEP '\\' -#else -#define DIRSEP '/' -#endif - -static CURLcode file_upload(struct connectdata *conn) -{ - struct FILEPROTO *file = conn->data->reqdata.proto.file; - char *dir = strchr(file->path, DIRSEP); - FILE *fp; - CURLcode res=CURLE_OK; - struct SessionHandle *data = conn->data; - char *buf = data->state.buffer; - size_t nread; - size_t nwrite; - curl_off_t bytecount = 0; - struct timeval now = Curl_tvnow(); - - /* - * Since FILE: doesn't do the full init, we need to provide some extra - * assignments here. - */ - conn->fread = data->set.fread; - conn->fread_in = data->set.in; - conn->data->reqdata.upload_fromhere = buf; - - if(!dir) - return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ - - if(!dir[1]) - return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ - - fp = fopen(file->path, "wb"); - if(!fp) { - failf(data, "Can't open %s for writing", file->path); - return CURLE_WRITE_ERROR; - } - - if(-1 != data->set.infilesize) - /* known size of data to "upload" */ - Curl_pgrsSetUploadSize(data, data->set.infilesize); - - while (res == CURLE_OK) { - int readcount; - res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); - if(res) - break; - - if (readcount <= 0) /* fix questionable compare error. curlvms */ - break; - - nread = (size_t)readcount; - - /* write the data to the target */ - nwrite = fwrite(buf, 1, nread, fp); - if(nwrite != nread) { - res = CURLE_SEND_ERROR; - break; - } - - bytecount += nread; - - Curl_pgrsSetUploadCounter(data, bytecount); - - if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; - else - res = Curl_speedcheck(data, now); - } - if(!res && Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; - - fclose(fp); - - return res; -} - -/* - * Curl_file() 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 don't allow select()ing etc on file handles (as - * opposed to sockets) we instead perform the whole do-operation in this - * function. - */ -CURLcode Curl_file(struct connectdata *conn, bool *done) -{ - /* 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 - */ - CURLcode res = CURLE_OK; - struct_stat statbuf; /* struct_stat instead of struct stat just to allow the - Windows version to have a different struct without - having to redefine the simple word 'stat' */ - curl_off_t expected_size=0; - bool fstated=FALSE; - ssize_t nread; - struct SessionHandle *data = conn->data; - char *buf = data->state.buffer; - curl_off_t bytecount = 0; - int fd; - struct timeval now = Curl_tvnow(); - - *done = TRUE; /* unconditionally */ - - Curl_readwrite_init(conn); - Curl_initinfo(data); - Curl_pgrsStartNow(data); - - if(data->set.upload) - return file_upload(conn); - - /* get the fd from the connection phase */ - fd = conn->data->reqdata.proto.file->fd; - - /* VMS: This only works reliable for STREAMLF files */ - if( -1 != fstat(fd, &statbuf)) { - /* we could stat it, then read out the size */ - expected_size = statbuf.st_size; - fstated = TRUE; - } - - /* If we have selected NOBODY and HEADER, it means that we only want file - information. Which for FILE can't be much more than the file size and - date. */ - if(conn->bits.no_body && data->set.include_header && fstated) { - CURLcode result; - snprintf(buf, sizeof(data->state.buffer), - "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - if(result) - return result; - - result = Curl_client_write(conn, CLIENTWRITE_BOTH, - (char *)"Accept-ranges: bytes\r\n", 0); - if(result) - return result; - - if(fstated) { - struct tm *tm; - time_t clock = (time_t)statbuf.st_mtime; -#ifdef HAVE_GMTIME_R - struct tm buffer; - tm = (struct tm *)gmtime_r(&clock, &buffer); -#else - tm = gmtime(&clock); -#endif - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(buf, BUFSIZE-1, - "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); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - } - return result; - } - - if (data->reqdata.resume_from <= expected_size) - expected_size -= data->reqdata.resume_from; - else { - failf(data, "failed to resume file:// transfer"); - return CURLE_BAD_DOWNLOAD_RESUME; - } - - if (fstated && (expected_size == 0)) - return CURLE_OK; - - /* The following is a shortcut implementation of file reading - this is both more efficient than the former call to download() and - it avoids problems with select() and recv() on file descriptors - in Winsock */ - if(fstated) - Curl_pgrsSetDownloadSize(data, expected_size); - - if(data->reqdata.resume_from) { - if(data->reqdata.resume_from != - lseek(fd, data->reqdata.resume_from, SEEK_SET)) - return CURLE_BAD_DOWNLOAD_RESUME; - } - - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - - while (res == CURLE_OK) { - nread = read(fd, buf, BUFSIZE-1); - - if ( nread > 0) - buf[nread] = 0; - - if (nread <= 0) - break; - - bytecount += nread; - - res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); - if(res) - return res; - - Curl_pgrsSetDownloadCounter(data, bytecount); - - if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; - else - res = Curl_speedcheck(data, now); - } - if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; - - return res; -} - -#endif diff --git a/Utilities/cmcurl/file.h b/Utilities/cmcurl/file.h deleted file mode 100644 index 20a1c4c..0000000 --- a/Utilities/cmcurl/file.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __FILE_H -#define __FILE_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_FILE -CURLcode Curl_file(struct connectdata *, bool *done); -CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature); -CURLcode Curl_file_connect(struct connectdata *); -#endif -#endif diff --git a/Utilities/cmcurl/formdata.c b/Utilities/cmcurl/formdata.c deleted file mode 100644 index f10c6c7..0000000 --- a/Utilities/cmcurl/formdata.c +++ /dev/null @@ -1,1694 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - Debug the form generator stand-alone by compiling this source file with: - - gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c - - run the 'formdata' executable the output should end with: - All Tests seem to have worked ... - and the following parts should be there: - -Content-Disposition: form-data; name="simple_COPYCONTENTS" -value for simple COPYCONTENTS - -Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE" -Content-Type: image/gif -value for COPYCONTENTS + CONTENTTYPE - -Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH" -vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH -(or you might see P^@RNAME and v^@lue at the start) - -Content-Disposition: form-data; name="simple_PTRCONTENTS" -value for simple PTRCONTENTS - -Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH" -vlue for PTRCONTENTS + CONTENTSLENGTH -(or you might see v^@lue at the start) - -Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE" -Content-Type: text/plain -vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE -(or you might see v^@lue at the start) - -Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h" -Content-Type: text/html -... - -Content-Disposition: form-data; name="FILE1_+_FILE2" -Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz -... -Content-Disposition: attachment; filename="inet_ntoa_r.h" -Content-Type: text/plain -... -Content-Disposition: attachment; filename="Makefile.b32" -Content-Type: text/plain -... - -Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3" -Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1 -... -Content-Disposition: attachment; filename="inet_ntoa_r.h" -Content-Type: text/plain -... -Content-Disposition: attachment; filename="Makefile.b32" -Content-Type: text/plain -... -Content-Disposition: attachment; filename="inet_ntoa_r.h" -Content-Type: text/plain -... - - -Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3" -Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1 -... -Content-Disposition: attachment; filename="inet_ntoa_r.h" -Content-Type: text/plain -... -Content-Disposition: attachment; filename="Makefile.b32" -Content-Type: text/plain -... -Content-Disposition: attachment; filename="inet_ntoa_r.h" -Content-Type: text/plain -... - -Content-Disposition: form-data; name="FILECONTENT" -... - - */ - -#include "setup.h" -#include - -/* Length of the random boundary string. */ -#define BOUNDARY_LENGTH 40 - -#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_STAT_H -#include -#endif -#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) -#include -#endif -#include "urldata.h" /* for struct SessionHandle */ -#include "easyif.h" /* for Curl_convert_... prototypes */ -#include "formdata.h" -#include "strequal.h" -#include "memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */ - -#ifndef CURL_DISABLE_HTTP - -#if defined(HAVE_BASENAME) && defined(NEED_BASENAME_PROTO) -/* This system has a basename() but no prototype for it! */ -char *basename(char *path); -#endif - -static size_t readfromfile(struct Form *form, char *buffer, size_t size); - -/* What kind of Content-Type to use on un-specified files with unrecognized - extensions. */ -#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream" - -#define FORM_FILE_SEPARATOR ',' -#define FORM_TYPE_SEPARATOR ';' - -/*************************************************************************** - * - * AddHttpPost() - * - * Adds a HttpPost structure to the list, if parent_post is given becomes - * a subpost of parent_post instead of a direct list element. - * - * Returns newly allocated HttpPost on success and NULL if malloc failed. - * - ***************************************************************************/ -static struct curl_httppost * -AddHttpPost(char * name, size_t namelength, - char * value, size_t contentslength, - char * buffer, size_t bufferlength, - char *contenttype, - long flags, - struct curl_slist* contentHeader, - char *showfilename, - struct curl_httppost *parent_post, - struct curl_httppost **httppost, - struct curl_httppost **last_post) -{ - struct curl_httppost *post; - post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1); - if(post) { - post->name = name; - post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); - post->contents = value; - post->contentslength = (long)contentslength; - post->buffer = buffer; - post->bufferlength = (long)bufferlength; - post->contenttype = contenttype; - post->contentheader = contentHeader; - post->showfilename = showfilename; - post->flags = flags; - } - else - return NULL; - - if (parent_post) { - /* now, point our 'more' to the original 'more' */ - post->more = parent_post->more; - - /* then move the original 'more' to point to ourselves */ - parent_post->more = post; - } - else { - /* make the previous point to this */ - if(*last_post) - (*last_post)->next = post; - else - (*httppost) = post; - - (*last_post) = post; - } - return post; -} - -/*************************************************************************** - * - * AddFormInfo() - * - * Adds a FormInfo structure to the list presented by parent_form_info. - * - * Returns newly allocated FormInfo on success and NULL if malloc failed/ - * parent_form_info is NULL. - * - ***************************************************************************/ -static FormInfo * AddFormInfo(char *value, - char *contenttype, - FormInfo *parent_form_info) -{ - FormInfo *form_info; - form_info = (FormInfo *)malloc(sizeof(FormInfo)); - if(form_info) { - memset(form_info, 0, sizeof(FormInfo)); - if (value) - form_info->value = value; - if (contenttype) - form_info->contenttype = contenttype; - form_info->flags = HTTPPOST_FILENAME; - } - else - return NULL; - - if (parent_form_info) { - /* now, point our 'more' to the original 'more' */ - form_info->more = parent_form_info->more; - - /* then move the original 'more' to point to ourselves */ - parent_form_info->more = form_info; - } - else - return NULL; - - return form_info; -} - -/*************************************************************************** - * - * ContentTypeForFilename() - * - * Provides content type for filename if one of the known types (else - * (either the prevtype or the default is returned). - * - * Returns some valid contenttype for filename. - * - ***************************************************************************/ -static const char * ContentTypeForFilename (const char *filename, - const char *prevtype) -{ - const char *contenttype = NULL; - unsigned int i; - /* - * No type was specified, we scan through a few well-known - * extensions and pick the first we match! - */ - struct ContentType { - const char *extension; - const char *type; - }; - static const struct ContentType ctts[]={ - {".gif", "image/gif"}, - {".jpg", "image/jpeg"}, - {".jpeg", "image/jpeg"}, - {".txt", "text/plain"}, - {".html", "text/html"} - }; - - if(prevtype) - /* default to the previously set/used! */ - contenttype = prevtype; - else - /* It seems RFC1867 defines no Content-Type to default to - text/plain so we don't actually need to set this: */ - contenttype = HTTPPOST_CONTENTTYPE_DEFAULT; - - for(i=0; i= strlen(ctts[i].extension)) { - if(strequal(filename + - strlen(filename) - strlen(ctts[i].extension), - ctts[i].extension)) { - contenttype = ctts[i].type; - break; - } - } - } - /* we have a contenttype by now */ - return contenttype; -} - -/*************************************************************************** - * - * memdup() - * - * Copies the 'source' data to a newly allocated buffer buffer (that is - * returned). Uses buffer_length if not null, else uses strlen to determine - * the length of the buffer to be copied - * - * Returns the new pointer or NULL on failure. - * - ***************************************************************************/ -static char *memdup(const char *src, size_t buffer_length) -{ - size_t length; - bool add = FALSE; - char *buffer; - - if (buffer_length) - length = buffer_length; - else { - length = strlen(src); - add = TRUE; - } - buffer = (char*)malloc(length+add); - if (!buffer) - return NULL; /* fail */ - - memcpy(buffer, src, length); - - /* if length unknown do null termination */ - if (add) - buffer[length] = '\0'; - - return buffer; -} - -/*************************************************************************** - * - * FormAdd() - * - * Stores a formpost parameter and builds the appropriate linked list. - * - * Has two principal functionalities: using files and byte arrays as - * post parts. Byte arrays are either copied or just the pointer is stored - * (as the user requests) while for files only the filename and not the - * content is stored. - * - * While you may have only one byte array for each name, multiple filenames - * are allowed (and because of this feature CURLFORM_END is needed after - * using CURLFORM_FILE). - * - * Examples: - * - * Simple name/value pair with copied contents: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); - * - * name/value pair where only the content pointer is remembered: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); - * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) - * - * storing a filename (CONTENTTYPE is optional!): - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", - * CURLFORM_END); - * - * storing multiple filenames: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); - * - * Returns: - * CURL_FORMADD_OK on success - * CURL_FORMADD_MEMORY if the FormInfo allocation fails - * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form - * CURL_FORMADD_NULL if a null pointer was given for a char - * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed - * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used - * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error) - * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated - * CURL_FORMADD_MEMORY if some allocation for string copying failed. - * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array - * - ***************************************************************************/ - -static -CURLFORMcode FormAdd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - va_list params) -{ - FormInfo *first_form, *current_form, *form = NULL; - CURLFORMcode return_value = CURL_FORMADD_OK; - const char *prevtype = NULL; - struct curl_httppost *post = NULL; - CURLformoption option; - 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're parsing an - array that we got passed to us. If FALSE we're parsing the input - va_list arguments. */ - bool array_state = FALSE; - - /* - * We need to allocate the first struct to fill in. - */ - first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1); - if(!first_form) - return CURL_FORMADD_MEMORY; - - current_form = first_form; - - /* - * Loop through all the options set. Break if we have an error to report. - */ - while (return_value == CURL_FORMADD_OK) { - - /* first see if we have more parts of the array param */ - if ( array_state ) { - /* get the upcoming option from the given array */ - option = forms->option; - array_value = (char *)forms->value; - - forms++; /* advance this to next entry */ - if (CURLFORM_END == option) { - /* end of array state */ - array_state = FALSE; - continue; - } - } - else { - /* This is not array-state, get next option */ - option = va_arg(params, CURLformoption); - if (CURLFORM_END == option) - break; - } - - switch (option) { - case CURLFORM_ARRAY: - if(array_state) - /* we don't support an array from within an array */ - return_value = CURL_FORMADD_ILLEGAL_ARRAY; - else { - forms = va_arg(params, struct curl_forms *); - if (forms) - array_state = TRUE; - else - return_value = CURL_FORMADD_NULL; - } - break; - - /* - * Set the Name property. - */ - case CURLFORM_PTRNAME: -#ifdef CURL_DOES_CONVERSIONS - /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll - have safe memory for the eventual conversion */ -#else - current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ -#endif - case CURLFORM_COPYNAME: - if (current_form->name) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *name = array_state? - array_value:va_arg(params, char *); - if (name) - current_form->name = name; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - case CURLFORM_NAMELENGTH: - if (current_form->namelength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->namelength = - array_state?(long)array_value:(long)va_arg(params, long); - break; - - /* - * Set the contents property. - */ - case CURLFORM_PTRCONTENTS: - current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */ - case CURLFORM_COPYCONTENTS: - if (current_form->value) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *value = - array_state?array_value:va_arg(params, char *); - if (value) - current_form->value = value; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - case CURLFORM_CONTENTSLENGTH: - if (current_form->contentslength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentslength = - array_state?(long)array_value:va_arg(params, long); - break; - - /* Get contents from a given file name */ - case CURLFORM_FILECONTENT: - if (current_form->flags != 0) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *filename = array_state? - array_value:va_arg(params, char *); - if (filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - else { - current_form->flags |= HTTPPOST_READFILE; - current_form->value_alloc = TRUE; - } - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - /* We upload a file */ - case CURLFORM_FILE: - { - char *filename = array_state?array_value: - va_arg(params, char *); - - if (current_form->value) { - if (current_form->flags & HTTPPOST_FILENAME) { - if (filename) { - if ((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if (filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - else { - current_form->flags |= HTTPPOST_FILENAME; - current_form->value_alloc = TRUE; - } - } - else - return_value = CURL_FORMADD_NULL; - } - break; - } - - case CURLFORM_BUFFER: - { - char *filename = array_state?array_value: - va_arg(params, char *); - - if (current_form->value) { - if (current_form->flags & HTTPPOST_BUFFER) { - if (filename) { - if ((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if (filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - current_form->flags |= HTTPPOST_BUFFER; - } - break; - } - - case CURLFORM_BUFFERPTR: - current_form->flags |= HTTPPOST_PTRBUFFER; - if (current_form->buffer) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *buffer = - array_state?array_value:va_arg(params, char *); - if (buffer) - current_form->buffer = buffer; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - - case CURLFORM_BUFFERLENGTH: - if (current_form->bufferlength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->bufferlength = - array_state?(long)array_value:va_arg(params, long); - break; - - case CURLFORM_CONTENTTYPE: - { - char *contenttype = - array_state?array_value:va_arg(params, char *); - if (current_form->contenttype) { - if (current_form->flags & HTTPPOST_FILENAME) { - if (contenttype) { - if ((current_form = AddFormInfo(NULL, - strdup(contenttype), - current_form)) == NULL) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if (contenttype) { - current_form->contenttype = strdup(contenttype); - if(!current_form->contenttype) - return_value = CURL_FORMADD_MEMORY; - else - current_form->contenttype_alloc = TRUE; - } - else - return_value = CURL_FORMADD_NULL; - } - break; - } - case CURLFORM_CONTENTHEADER: - { - /* this "cast increases required alignment of target type" but - we consider it OK anyway */ - struct curl_slist* list = array_state? - (struct curl_slist*)array_value: - va_arg(params, struct curl_slist*); - - if( current_form->contentheader ) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentheader = list; - - break; - } - case CURLFORM_FILENAME: - { - char *filename = array_state?array_value: - va_arg(params, char *); - if( current_form->showfilename ) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - current_form->showfilename = strdup(filename); - if(!current_form->showfilename) - return_value = CURL_FORMADD_MEMORY; - else - current_form->showfilename_alloc = TRUE; - } - break; - } - default: - return_value = CURL_FORMADD_UNKNOWN_OPTION; - } - } - - if(CURL_FORMADD_OK == return_value) { - /* go through the list, check for copleteness and if everything is - * alright add the HttpPost item otherwise set return_value accordingly */ - - post = NULL; - for(form = first_form; - form != NULL; - form = form->more) { - if ( ((!form->name || !form->value) && !post) || - ( (form->contentslength) && - (form->flags & HTTPPOST_FILENAME) ) || - ( (form->flags & HTTPPOST_FILENAME) && - (form->flags & HTTPPOST_PTRCONTENTS) ) || - - ( (!form->buffer) && - (form->flags & HTTPPOST_BUFFER) && - (form->flags & HTTPPOST_PTRBUFFER) ) || - - ( (form->flags & HTTPPOST_READFILE) && - (form->flags & HTTPPOST_PTRCONTENTS) ) - ) { - return_value = CURL_FORMADD_INCOMPLETE; - break; - } - else { - if ( ((form->flags & HTTPPOST_FILENAME) || - (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype ) { - /* our contenttype is missing */ - form->contenttype - = strdup(ContentTypeForFilename(form->value, prevtype)); - if(!form->contenttype) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->contenttype_alloc = TRUE; - } - if ( !(form->flags & HTTPPOST_PTRNAME) && - (form == first_form) ) { - /* copy name (without strdup; possibly contains null characters) */ - form->name = memdup(form->name, form->namelength); - if (!form->name) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->name_alloc = TRUE; - } - if ( !(form->flags & HTTPPOST_FILENAME) && - !(form->flags & HTTPPOST_READFILE) && - !(form->flags & HTTPPOST_PTRCONTENTS) && - !(form->flags & HTTPPOST_PTRBUFFER) ) { - /* copy value (without strdup; possibly contains null characters) */ - form->value = memdup(form->value, form->contentslength); - if (!form->value) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->value_alloc = TRUE; - } - post = AddHttpPost(form->name, form->namelength, - form->value, form->contentslength, - form->buffer, form->bufferlength, - form->contenttype, form->flags, - form->contentheader, form->showfilename, - post, httppost, - last_post); - - if(!post) { - return_value = CURL_FORMADD_MEMORY; - break; - } - - if (form->contenttype) - prevtype = form->contenttype; - } - } - } - - if(return_value) { - /* we return on error, free possibly allocated fields */ - if(!form) - form = current_form; - if(form) { - if(form->name_alloc) - free(form->name); - if(form->value_alloc) - free(form->value); - if(form->contenttype_alloc) - free(form->contenttype); - if(form->showfilename_alloc) - free(form->showfilename); - } - } - - /* always delete the allocated memory before returning */ - form = first_form; - while (form != NULL) { - FormInfo *delete_form; - - delete_form = form; - form = form->more; - free (delete_form); - } - - return return_value; -} - -/* - * curl_formadd() is a public API to add a section to the multipart formpost. - */ - -CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - va_list arg; - CURLFORMcode result; - va_start(arg, last_post); - result = FormAdd(httppost, last_post, arg); - va_end(arg); - return result; -} - -/* - * AddFormData() adds a chunk of data to the FormData linked list. - * - * size is incremented by the chunk length, unless it is NULL - */ -static CURLcode AddFormData(struct FormData **formp, - enum formtype type, - const void *line, - size_t length, - curl_off_t *size) -{ - struct FormData *newform = (struct FormData *) - malloc(sizeof(struct FormData)); - if (!newform) - return CURLE_OUT_OF_MEMORY; - newform->next = NULL; - - /* we make it easier for plain strings: */ - if(!length) - length = strlen((char *)line); - - newform->line = (char *)malloc(length+1); - if (!newform->line) { - free(newform); - return CURLE_OUT_OF_MEMORY; - } - memcpy(newform->line, line, length); - newform->length = length; - newform->line[length]=0; /* zero terminate for easier debugging */ - newform->type = type; - - if(*formp) { - (*formp)->next = newform; - *formp = newform; - } - else - *formp = newform; - - if (size) { - if((type == FORM_DATA) || (type == FORM_CONTENT)) - *size += length; - else { - /* Since this is a file to be uploaded here, add the size of the actual - file */ - if(!strequal("-", newform->line)) { - struct_stat file; - if(!stat(newform->line, &file)) { - *size += file.st_size; - } - } - } - } - return CURLE_OK; -} - -/* - * AddFormDataf() adds printf()-style formatted data to the formdata chain. - */ - -static CURLcode AddFormDataf(struct FormData **formp, - curl_off_t *size, - const char *fmt, ...) -{ - char s[4096]; - va_list ap; - va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); - va_end(ap); - - return AddFormData(formp, FORM_DATA, s, 0, size); -} - -/* - * Curl_formclean() is used from http.c, this cleans a built FormData linked - * list - */ -void Curl_formclean(struct FormData **form_ptr) -{ - struct FormData *next, *form; - - form = *form_ptr; - if(!form) - return; - - do { - next=form->next; /* the following form line */ - free(form->line); /* free the line */ - free(form); /* free the struct */ - - } while ((form = next) != NULL); /* continue */ - - *form_ptr = NULL; -} - -#ifdef CURL_DOES_CONVERSIONS -/* - * Curl_formcovert() is used from http.c, this converts any - form items that need to be sent in the network encoding. - Returns CURLE_OK on success. - */ -CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form) -{ - struct FormData *next; - CURLcode rc; - - if(!form) - return CURLE_OK; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - do { - next=form->next; /* the following form line */ - if (form->type == FORM_DATA) { - rc = Curl_convert_to_network(data, form->line, form->length); - /* Curl_convert_to_network calls failf if unsuccessful */ - if (rc != CURLE_OK) - return rc; - } - } while ((form = next) != NULL); /* continue */ - return CURLE_OK; -} -#endif /* CURL_DOES_CONVERSIONS */ - -/* - * curl_formget() - * Serialize a curl_httppost struct. - * Returns 0 on success. - */ -int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append) -{ - CURLcode rc; - curl_off_t size; - struct FormData *data, *ptr; - - rc = Curl_getFormData(&data, form, NULL, &size); - if (rc != CURLE_OK) - return (int)rc; - - for (ptr = data; ptr; ptr = ptr->next) { - if (ptr->type == FORM_FILE) { - char buffer[8192]; - size_t read; - struct Form temp; - - Curl_FormInit(&temp, ptr); - - do { - read = readfromfile(&temp, buffer, sizeof(buffer)); - if ((read == (size_t) -1) || (read != append(arg, buffer, read))) { - if (temp.fp) { - fclose(temp.fp); - } - Curl_formclean(&data); - return -1; - } - } while (read == sizeof(buffer)); - } else { - if (ptr->length != append(arg, ptr->line, ptr->length)) { - Curl_formclean(&data); - return -1; - } - } - } - Curl_formclean(&data); - return 0; -} - -/* - * curl_formfree() is an external function to free up a whole form post - * chain - */ -void curl_formfree(struct curl_httppost *form) -{ - struct curl_httppost *next; - - if(!form) - /* no form to free, just get out of this */ - return; - - do { - next=form->next; /* the following form line */ - - /* recurse to sub-contents */ - if(form->more) - curl_formfree(form->more); - - if( !(form->flags & HTTPPOST_PTRNAME) && form->name) - free(form->name); /* free the name */ - if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents) - free(form->contents); /* free the contents */ - if(form->contenttype) - free(form->contenttype); /* free the content type */ - if(form->showfilename) - free(form->showfilename); /* free the faked file name */ - free(form); /* free the struct */ - - } while ((form = next) != NULL); /* continue */ -} - -#ifndef HAVE_BASENAME -/* - (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 - Edition) - - The basename() function shall take the pathname pointed to by path and - return a pointer to the final component of the pathname, deleting any - trailing '/' characters. - - If the string pointed to by path consists entirely of the '/' character, - basename() shall return a pointer to the string "/". If the string pointed - to by path is exactly "//", it is implementation-defined whether '/' or "//" - is returned. - - If path is a null pointer or points to an empty string, basename() shall - return a pointer to the string ".". - - The basename() function may modify the string pointed to by path, and may - return a pointer to static storage that may then be overwritten by a - subsequent call to basename(). - - The basename() function need not be reentrant. A function that is not - required to be reentrant is not required to be thread-safe. - -*/ -static char *basename(char *path) -{ - /* Ignore all the details above for now and make a quick and simple - implementaion here */ - char *s1; - char *s2; - - s1=strrchr(path, '/'); - s2=strrchr(path, '\\'); - - if(s1 && s2) { - path = (s1 > s2? s1 : s2)+1; - } - else if(s1) - path = s1 + 1; - else if(s2) - path = s2 + 1; - - return path; -} -#endif - -static char *strippath(char *fullfile) -{ - char *filename; - char *base; - filename = strdup(fullfile); /* duplicate since basename() may ruin the - buffer it works on */ - if(!filename) - return NULL; - base = strdup(basename(filename)); - - free(filename); /* free temporary buffer */ - - return base; /* returns an allocated string! */ -} - -/* - * Curl_getFormData() converts a linked list of "meta data" into a complete - * (possibly huge) multipart formdata. The input list is in 'post', while the - * output resulting linked lists gets stored in '*finalform'. *sizep will get - * the total size of the whole POST. - * A multipart/form_data content-type is built, unless a custom content-type - * is passed in 'custom_content_type'. - */ - -CURLcode Curl_getFormData(struct FormData **finalform, - struct curl_httppost *post, - const char *custom_content_type, - curl_off_t *sizep) -{ - struct FormData *form = NULL; - struct FormData *firstform; - struct curl_httppost *file; - CURLcode result = CURLE_OK; - - curl_off_t size=0; /* support potentially ENORMOUS formposts */ - char *boundary; - char *fileboundary=NULL; - struct curl_slist* curList; - - *finalform=NULL; /* default form is empty */ - - if(!post) - return result; /* no input => no output! */ - - boundary = Curl_FormBoundary(); - if(!boundary) - return CURLE_OUT_OF_MEMORY; - - /* Make the first line of the output */ - result = AddFormDataf(&form, NULL, - "%s; boundary=%s\r\n", - custom_content_type?custom_content_type: - "Content-Type: multipart/form-data", - boundary); - - if (result) { - free(boundary); - return result; - } - /* we DO NOT include that line in the total size of the POST, since it'll be - part of the header! */ - - firstform = form; - - do { - - if(size) { - result = AddFormDataf(&form, &size, "\r\n"); - if (result) - break; - } - - /* boundary */ - result = AddFormDataf(&form, &size, "--%s\r\n", boundary); - if (result) - break; - - /* Maybe later this should be disabled when a custom_content_type is - passed, since Content-Disposition is not meaningful for all multipart - types. - */ - result = AddFormDataf(&form, &size, - "Content-Disposition: form-data; name=\""); - if (result) - break; - - result = AddFormData(&form, FORM_DATA, post->name, post->namelength, - &size); - if (result) - break; - - result = AddFormDataf(&form, &size, "\""); - if (result) - break; - - if(post->more) { - /* If used, this is a link to more file names, we must then do - the magic to include several files with the same field name */ - - fileboundary = Curl_FormBoundary(); - - result = AddFormDataf(&form, &size, - "\r\nContent-Type: multipart/mixed," - " boundary=%s\r\n", - fileboundary); - if (result) - break; - } - - file = post; - - do { - - /* If 'showfilename' is set, that is a faked name passed on to us - to use to in the formpost. If that is not set, the actually used - local file name should be added. */ - - if(post->more) { - /* if multiple-file */ - char *filebasename= - (!file->showfilename)?strippath(file->contents):NULL; - - result = AddFormDataf(&form, &size, - "\r\n--%s\r\nContent-Disposition: " - "attachment; filename=\"%s\"", - fileboundary, - (file->showfilename?file->showfilename: - filebasename)); - if (filebasename) - free(filebasename); - if (result) - break; - } - else if((post->flags & HTTPPOST_FILENAME) || - (post->flags & HTTPPOST_BUFFER)) { - - char *filebasename= - (!post->showfilename)?strippath(post->contents):NULL; - - result = AddFormDataf(&form, &size, - "; filename=\"%s\"", - (post->showfilename?post->showfilename: - filebasename)); - if (filebasename) - free(filebasename); - - if (result) - break; - } - - if(file->contenttype) { - /* we have a specified type */ - result = AddFormDataf(&form, &size, - "\r\nContent-Type: %s", - file->contenttype); - if (result) - break; - } - - curList = file->contentheader; - while( curList ) { - /* Process the additional headers specified for this form */ - result = AddFormDataf( &form, &size, "\r\n%s", curList->data ); - if (result) - break; - curList = curList->next; - } - if (result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } - -#if 0 - /* The header Content-Transfer-Encoding: seems to confuse some receivers - * (like the built-in PHP engine). While I can't see any reason why it - * should, I can just as well skip this to the benefit of the users who - * are using such confused receivers. - */ - - if(file->contenttype && - !checkprefix("text/", file->contenttype)) { - /* this is not a text content, mention our binary encoding */ - result = AddFormDataf(&form, &size, - "\r\nContent-Transfer-Encoding: binary"); - if (result) - break; - } -#endif - - result = AddFormDataf(&form, &size, "\r\n\r\n"); - if (result) - break; - - if((post->flags & HTTPPOST_FILENAME) || - (post->flags & HTTPPOST_READFILE)) { - /* we should include the contents from the specified file */ - FILE *fileread; - - fileread = strequal("-", file->contents)? - stdin:fopen(file->contents, "rb"); /* binary read for win32 */ - - /* - * VMS: This only allows for stream files on VMS. Stream files are - * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC, - * every record needs to have a \n appended & 1 added to SIZE - */ - - if(fileread) { - if(fileread != stdin) { - /* close the file again */ - fclose(fileread); - /* add the file name only - for later reading from this */ - result = AddFormData(&form, FORM_FILE, file->contents, 0, &size); - } - else { - /* When uploading from stdin, we can't know the size of the file, - * thus must read the full file as before. We *could* use chunked - * transfer-encoding, but that only works for HTTP 1.1 and we - * can't be sure we work with such a server. - */ - size_t nread; - char buffer[512]; - while ((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { - result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); - if (result) - break; - } - } - - if (result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } - - } - else { -#ifdef _FORM_DEBUG - fprintf(stderr, - "\n==> Curl_getFormData couldn't open/read \"%s\"\n", - file->contents); -#endif - Curl_formclean(&firstform); - free(boundary); - *finalform = NULL; - return CURLE_READ_ERROR; - } - - } - else if (post->flags & HTTPPOST_BUFFER) { - /* include contents of buffer */ - result = AddFormData(&form, FORM_CONTENT, post->buffer, - post->bufferlength, &size); - if (result) - break; - } - - else { - /* include the contents we got */ - result = AddFormData(&form, FORM_CONTENT, post->contents, - post->contentslength, &size); - if (result) - break; - } - } while ((file = file->more) != NULL); /* for each specified file for this field */ - if (result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } - - if(post->more) { - /* this was a multiple-file inclusion, make a termination file - boundary: */ - result = AddFormDataf(&form, &size, - "\r\n--%s--", - fileboundary); - free(fileboundary); - if (result) - break; - } - - } while ((post = post->next) != NULL); /* for each field */ - if (result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } - - /* end-boundary for everything */ - result = AddFormDataf(&form, &size, - "\r\n--%s--\r\n", - boundary); - if (result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } - - *sizep = size; - - free(boundary); - - *finalform=firstform; - - return result; -} - -/* - * Curl_FormInit() inits the struct 'form' points to with the 'formdata' - * and resets the 'sent' counter. - */ -int Curl_FormInit(struct Form *form, struct FormData *formdata ) -{ - if(!formdata) - return 1; /* error */ - - form->data = formdata; - form->sent = 0; - form->fp = NULL; - - return 0; -} - -static size_t readfromfile(struct Form *form, char *buffer, size_t size) -{ - size_t nread; - if(!form->fp) { - /* this file hasn't yet been opened */ - form->fp = fopen(form->data->line, "rb"); /* b is for binary */ - if(!form->fp) - return (size_t)-1; /* failure */ - } - nread = fread(buffer, 1, size, form->fp); - - if(nread != size) { - /* this is the last chunk from the file, move on */ - fclose(form->fp); - form->fp = NULL; - form->data = form->data->next; - } - - return nread; -} - -/* - * Curl_FormReader() is the fread() emulation function that will be used to - * deliver the formdata to the transfer loop and then sent away to the peer. - */ -size_t Curl_FormReader(char *buffer, - size_t size, - size_t nitems, - FILE *mydata) -{ - struct Form *form; - size_t wantedsize; - size_t gotsize = 0; - - form=(struct Form *)mydata; - - wantedsize = size * nitems; - - if(!form->data) - return 0; /* nothing, error, empty */ - - if(form->data->type == FORM_FILE) { - gotsize = readfromfile(form, buffer, wantedsize); - - if(gotsize) - /* If positive or -1, return. If zero, continue! */ - return gotsize; - } - do { - - if( (form->data->length - form->sent ) > wantedsize - gotsize) { - - memcpy(buffer + gotsize , form->data->line + form->sent, - wantedsize - gotsize); - - form->sent += wantedsize-gotsize; - - return wantedsize; - } - - memcpy(buffer+gotsize, - form->data->line + form->sent, - (form->data->length - form->sent) ); - gotsize += form->data->length - form->sent; - - form->sent = 0; - - form->data = form->data->next; /* advance */ - - } while(form->data && (form->data->type != FORM_FILE)); - /* If we got an empty line and we have more data, we proceed to the next - line immediately to avoid returning zero before we've reached the end. - This is the bug reported November 22 1999 on curl 6.3. (Daniel) */ - - return gotsize; -} - -/* - * Curl_formpostheader() returns the first line of the formpost, the - * request-header part (which is not part of the request-body like the rest of - * the post). - */ -char *Curl_formpostheader(void *formp, size_t *len) -{ - char *header; - struct Form *form=(struct Form *)formp; - - if(!form->data) - return 0; /* nothing, ERROR! */ - - header = form->data->line; - *len = form->data->length; - - form->data = form->data->next; /* advance */ - - return header; -} - - -#ifdef _FORM_DEBUG -int FormAddTest(const char * errormsg, - struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - int result; - va_list arg; - va_start(arg, last_post); - if ((result = FormAdd(httppost, last_post, arg))) - fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result, - errormsg); - va_end(arg); - return result; -} - - -int main() -{ - char name1[] = "simple_COPYCONTENTS"; - char name2[] = "COPYCONTENTS_+_CONTENTTYPE"; - char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"; - char name4[] = "simple_PTRCONTENTS"; - char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH"; - char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"; - char name7[] = "FILE1_+_CONTENTTYPE"; - char name8[] = "FILE1_+_FILE2"; - char name9[] = "FILE1_+_FILE2_+_FILE3"; - char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3"; - char name11[] = "FILECONTENT"; - char value1[] = "value for simple COPYCONTENTS"; - char value2[] = "value for COPYCONTENTS + CONTENTTYPE"; - char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH"; - char value4[] = "value for simple PTRCONTENTS"; - char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH"; - char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE"; - char value7[] = "inet_ntoa_r.h"; - char value8[] = "Makefile.b32"; - char type2[] = "image/gif"; - char type6[] = "text/plain"; - char type7[] = "text/html"; - int name3length = strlen(name3); - int value3length = strlen(value3); - int value5length = strlen(value4); - int value6length = strlen(value5); - int errors = 0; - CURLcode rc; - size_t size; - size_t nread; - char buffer[4096]; - struct curl_httppost *httppost=NULL; - struct curl_httppost *last_post=NULL; - struct curl_forms forms[4]; - - struct FormData *form; - struct Form formread; - - if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post, - CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1, - CURLFORM_END)) - ++errors; - if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post, - CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2, - CURLFORM_CONTENTTYPE, type2, CURLFORM_END)) - ++errors; - /* make null character at start to check that contentslength works - correctly */ - name3[1] = '\0'; - value3[1] = '\0'; - if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test", - &httppost, &last_post, - CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3, - CURLFORM_CONTENTSLENGTH, value3length, - CURLFORM_NAMELENGTH, name3length, CURLFORM_END)) - ++errors; - if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post, - CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4, - CURLFORM_END)) - ++errors; - /* make null character at start to check that contentslength works - correctly */ - value5[1] = '\0'; - if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post, - CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5, - CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END)) - ++errors; - /* make null character at start to check that contentslength works - correctly */ - value6[1] = '\0'; - if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test", - &httppost, &last_post, - CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6, - CURLFORM_CONTENTSLENGTH, value6length, - CURLFORM_CONTENTTYPE, type6, CURLFORM_END)) - ++errors; - if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post, - CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7, - CURLFORM_CONTENTTYPE, type7, CURLFORM_END)) - ++errors; - if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post, - CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7, - CURLFORM_FILE, value8, CURLFORM_END)) - ++errors; - if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post, - CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7, - CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END)) - ++errors; - forms[0].option = CURLFORM_FILE; - forms[0].value = value7; - forms[1].option = CURLFORM_FILE; - forms[1].value = value8; - forms[2].option = CURLFORM_FILE; - forms[2].value = value7; - forms[3].option = CURLFORM_END; - if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post, - CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms, - CURLFORM_END)) - ++errors; - if (FormAddTest("FILECONTENT test", &httppost, &last_post, - CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7, - CURLFORM_END)) - ++errors; - - rc = Curl_getFormData(&form, httppost, NULL, &size); - if(rc != CURLE_OK) { - if(rc != CURLE_READ_ERROR) { - const char *errortext = curl_easy_strerror(rc); - fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext); - } - return 0; - } - - Curl_FormInit(&formread, form); - - do { - nread = Curl_FormReader(buffer, 1, sizeof(buffer), - (FILE *)&formread); - - if(nread < 1) - break; - fwrite(buffer, nread, 1, stdout); - } while(1); - - fprintf(stdout, "size: %d\n", size); - if (errors) - fprintf(stdout, "\n==> %d Test(s) failed!\n", errors); - else - fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n"); - - return 0; -} - -#endif /* _FORM_DEBUG */ - -#else /* CURL_DISABLE_HTTP */ -CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - (void)httppost; - (void)last_post; - return CURL_FORMADD_DISABLED; -} - -int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append) -{ - (void) form; - (void) arg; - (void) append; - return CURL_FORMADD_DISABLED; -} - -void curl_formfree(struct curl_httppost *form) -{ - (void)form; - /* does nothing HTTP is disabled */ -} - -#endif /* CURL_DISABLE_HTTP */ - -#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) - -/* - * Curl_FormBoundary() creates a suitable boundary string and returns an - * allocated one. This is also used by SSL-code so it must be present even - * if HTTP is disabled! - */ -char *Curl_FormBoundary(void) -{ - char *retstring; - static int randomizer; /* this is just so that two boundaries within - the same form won't be identical */ - size_t i; - - static const char table16[]="abcdef0123456789"; - - retstring = (char *)malloc(BOUNDARY_LENGTH+1); - - if(!retstring) - return NULL; /* failed */ - - srand((unsigned int)time(NULL)+randomizer++); /* seed */ - - strcpy(retstring, "----------------------------"); - - for(i=strlen(retstring); i, 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -enum formtype { - FORM_DATA, /* form metadata (convert to network encoding if necessary) */ - FORM_CONTENT, /* form content (never convert) */ - FORM_FILE /* 'line' points to a file name we should read from - to create the form data (never convert) */ -}; - -/* plain and simple linked list with lines to send */ -struct FormData { - struct FormData *next; - enum formtype type; - char *line; - size_t length; -}; - -struct Form { - struct FormData *data; /* current form line to send */ - size_t sent; /* number of bytes of the current line that has - already been sent in a previous invoke */ - FILE *fp; /* file to read from */ -}; - -/* used by FormAdd for temporary storage */ -typedef struct FormInfo { - char *name; - bool name_alloc; - size_t namelength; - char *value; - bool value_alloc; - size_t contentslength; - char *contenttype; - bool contenttype_alloc; - long flags; - char *buffer; /* pointer to existing buffer used for file upload */ - size_t bufferlength; - char *showfilename; /* The file name to show. If not set, the actual - file name will be used */ - bool showfilename_alloc; - struct curl_slist* contentheader; - struct FormInfo *more; -} FormInfo; - -int Curl_FormInit(struct Form *form, struct FormData *formdata ); - -CURLcode -Curl_getFormData(struct FormData **, - struct curl_httppost *post, - const char *custom_contenttype, - curl_off_t *size); - -/* fread() emulation */ -size_t Curl_FormReader(char *buffer, - size_t size, - size_t nitems, - FILE *mydata); - -/* - * Curl_formpostheader() returns the first line of the formpost, the - * request-header part (which is not part of the request-body like the rest of - * the post). - */ -char *Curl_formpostheader(void *formp, size_t *len); - -char *Curl_FormBoundary(void); - -void Curl_formclean(struct FormData **); - -CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *); - -#endif - diff --git a/Utilities/cmcurl/ftp.c b/Utilities/cmcurl/ftp.c deleted file mode 100644 index 3ccbc43..0000000 --- a/Utilities/cmcurl/ftp.c +++ /dev/null @@ -1,3865 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_FTP -#include -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef WIN32 - -#else /* probably some kind of unix */ -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef VMS -#include -#include -#endif -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - -#include "if2ip.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "ftp.h" - -#ifdef HAVE_KRB4 -#include "krb4.h" -#endif - -#include "strtoofft.h" -#include "strequal.h" -#include "sslgen.h" -#include "connect.h" -#include "strerror.h" -#include "memory.h" -#include "inet_ntop.h" -#include "select.h" -#include "parsedate.h" /* for the week day and month names */ -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "multiif.h" - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#ifdef CURLDEBUG -#include "memdebug.h" -#endif - -#ifdef HAVE_NI_WITHSCOPEID -#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID -#else -#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV -#endif - -/* Local API functions */ -static CURLcode ftp_sendquote(struct connectdata *conn, - struct curl_slist *quote); -static CURLcode ftp_quit(struct connectdata *conn); -static CURLcode ftp_parse_url_path(struct connectdata *conn); -static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done); -static void ftp_pasv_verbose(struct connectdata *conn, - Curl_addrinfo *ai, - char *newhost, /* ascii version */ - int port); -static CURLcode ftp_state_post_rest(struct connectdata *conn); -static CURLcode ftp_state_post_cwd(struct connectdata *conn); -static CURLcode ftp_state_quote(struct connectdata *conn, - bool init, ftpstate instate); -static CURLcode ftp_nb_type(struct connectdata *conn, - bool ascii, ftpstate state); -static int ftp_need_type(struct connectdata *conn, - bool ascii); - -/* easy-to-use macro: */ -#define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \ - return result -#define NBFTPSENDF(x,y,z) if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \ - return result - -static void freedirs(struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - - int i; - if(ftpc->dirs) { - for (i=0; i < ftpc->dirdepth; i++){ - if(ftpc->dirs[i]) { - free(ftpc->dirs[i]); - ftpc->dirs[i]=NULL; - } - } - free(ftpc->dirs); - ftpc->dirs = NULL; - } - if(ftp->file) { - free(ftp->file); - ftp->file = NULL; - } -} - -/* Returns non-zero if the given string contains CR (\r) or LF (\n), - which are not allowed within RFC 959 . - Note: The input string is in the client's encoding which might - not be ASCII, so escape sequences \r & \n must be used instead - of hex values 0x0d & 0x0a. -*/ -static bool isBadFtpString(const char *string) -{ - return (bool)((NULL != strchr(string, '\r')) || (NULL != strchr(string, '\n'))); -} - -/*********************************************************************** - * - * AllowServerConnect() - * - * When we've issue the PORT command, we have told the server to connect - * to us. This function will sit and wait here until the server has - * connected. - * - */ -static CURLcode AllowServerConnect(struct connectdata *conn) -{ - int timeout_ms; - struct SessionHandle *data = conn->data; - curl_socket_t sock = conn->sock[SECONDARYSOCKET]; - struct timeval now = Curl_tvnow(); - long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000; - long timeout = data->set.connecttimeout?data->set.connecttimeout: - (data->set.timeout?data->set.timeout: 0); - - if(timeout) { - timeout -= timespent; - if(timeout<=0) { - failf(data, "Timed out before server could connect to us"); - return CURLE_OPERATION_TIMEDOUT; - } - } - - /* We allow the server 60 seconds to connect to us, or a custom timeout. - Note the typecast here. */ - timeout_ms = (timeout?(int)timeout:60) * 1000; - - switch (Curl_select(sock, CURL_SOCKET_BAD, timeout_ms)) { - case -1: /* error */ - /* let's die here */ - failf(data, "Error while waiting for server connect"); - return CURLE_FTP_PORT_FAILED; - case 0: /* timeout */ - /* let's die here */ - failf(data, "Timeout while waiting for server connect"); - return CURLE_FTP_PORT_FAILED; - default: - /* we have received data here */ - { - curl_socket_t s = CURL_SOCKET_BAD; -#ifdef ENABLE_IPV6 - struct Curl_sockaddr_storage add; -#else - struct sockaddr_in add; -#endif - socklen_t size = (socklen_t) sizeof(add); - - if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { - size = sizeof(add); - - s=accept(sock, (struct sockaddr *) &add, &size); - } - sclose(sock); /* close the first socket */ - - if (CURL_SOCKET_BAD == s) { - /* DIE! */ - failf(data, "Error accept()ing server connect"); - return CURLE_FTP_PORT_FAILED; - } - infof(data, "Connection accepted from server\n"); - - conn->sock[SECONDARYSOCKET] = s; - Curl_nonblock(s, TRUE); /* enable non-blocking */ - } - break; - } - - return CURLE_OK; -} - -/* initialize stuff to prepare for reading a fresh new response */ -static void ftp_respinit(struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - ftpc->nread_resp = 0; - ftpc->linestart_resp = conn->data->state.buffer; -} - -/* macro to check for the last line in an FTP server response */ -#define lastline(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ - ISDIGIT(line[2]) && (' ' == line[3])) - -static CURLcode ftp_readresp(curl_socket_t sockfd, - struct connectdata *conn, - int *ftpcode, /* return the ftp-code if done */ - size_t *size) /* size of the response */ -{ - int perline; /* count bytes per line */ - bool keepon=TRUE; - ssize_t gotbytes; - char *ptr; - struct SessionHandle *data = conn->data; - char *buf = data->state.buffer; - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - int code = 0; - - if (ftpcode) - *ftpcode = 0; /* 0 for errors or not done */ - - ptr=buf + ftpc->nread_resp; - - perline= (int)(ptr-ftpc->linestart_resp); /* number of bytes in the current - line, so far */ - keepon=TRUE; - - while((ftpc->nread_respcache) { - /* we had data in the "cache", copy that instead of doing an actual - * read - * - * ftp->cache_size is cast to int 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. - */ - memcpy(ptr, ftpc->cache, (int)ftpc->cache_size); - gotbytes = (int)ftpc->cache_size; - free(ftpc->cache); /* free the cache */ - ftpc->cache = NULL; /* clear the pointer */ - ftpc->cache_size = 0; /* zero the size just in case */ - } - else { - int res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp, - &gotbytes); - if(res < 0) - /* EWOULDBLOCK */ - return CURLE_OK; /* return */ - -#ifdef CURL_DOES_CONVERSIONS - if((res == CURLE_OK) && (gotbytes > 0)) { - /* convert from the network encoding */ - result = res = Curl_convert_from_network(data, ptr, gotbytes); - /* Curl_convert_from_network calls failf if unsuccessful */ - } -#endif /* CURL_DOES_CONVERSIONS */ - - if(CURLE_OK != res) - keepon = FALSE; - } - - if(!keepon) - ; - else if(gotbytes <= 0) { - keepon = FALSE; - result = CURLE_RECV_ERROR; - failf(data, "FTP response reading failed"); - } - 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 */ - int i; - - conn->headerbytecount += gotbytes; - - ftpc->nread_resp += gotbytes; - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; - if(*ptr=='\n') { - /* a newline is CRLF in ftp-talk, so the CR is ignored as - the line isn't really terminated until the LF comes */ - - /* output debug output if that is requested */ - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - ftpc->linestart_resp, (size_t)perline, conn); - - /* - * 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(conn, CLIENTWRITE_HEADER, - ftpc->linestart_resp, perline); - if(result) - return result; - - if(perline>3 && lastline(ftpc->linestart_resp)) { - /* This is the end of the last line, copy the last line to the - start of the buffer and zero terminate, for old times sake (and - krb4)! */ - char *meow; - int n; - for(meow=ftpc->linestart_resp, n=0; meowlinestart_resp = ptr+1; /* advance pointer */ - i++; /* skip this before getting out */ - - *size = ftpc->nread_resp; /* size of the response */ - ftpc->nread_resp = 0; /* restart */ - break; - } - perline=0; /* line starts over here */ - ftpc->linestart_resp = ptr+1; - } - } - 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! */ - ftpc->cache_size = gotbytes - i; - ftpc->cache = (char *)malloc((int)ftpc->cache_size); - if(ftpc->cache) - memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size); - else - return CURLE_OUT_OF_MEMORY; /**BANG**/ - } - } /* there was data */ - - } /* while there's buffer left and loop is requested */ - - if(!result) - code = atoi(buf); - -#ifdef HAVE_KRB4 - /* handle the security-oriented responses 6xx ***/ - /* FIXME: some errorchecking perhaps... ***/ - switch(code) { - case 631: - Curl_sec_read_msg(conn, buf, prot_safe); - break; - case 632: - Curl_sec_read_msg(conn, buf, prot_private); - break; - case 633: - Curl_sec_read_msg(conn, buf, prot_confidential); - break; - default: - /* normal ftp stuff we pass through! */ - break; - } -#endif - - *ftpcode=code; /* return the initial number like this */ - - - /* store the latest code for later retrieval */ - conn->data->info.httpcode=code; - - return result; -} - -/* --- parse FTP server responses --- */ - -/* - * Curl_GetFTPResponse() is supposed to be invoked after each command sent to - * a remote FTP server. This function will wait and read all lines of the - * response and extract the relevant return code for the invoking function. - */ - -CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ - struct connectdata *conn, - int *ftpcode) /* return the ftp-code */ -{ - /* - * We cannot read just one byte per read() and then go back to select() as - * 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. */ - - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - int perline; /* count bytes per line */ - bool keepon=TRUE; - ssize_t gotbytes; - char *ptr; - long timeout; /* timeout in seconds */ - int interval_ms; - struct SessionHandle *data = conn->data; - char *line_start; - int code=0; /* default ftp "error code" to return */ - char *buf = data->state.buffer; - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct timeval now = Curl_tvnow(); - - if (ftpcode) - *ftpcode = 0; /* 0 for errors */ - - ptr=buf; - line_start = buf; - - *nreadp=0; - perline=0; - keepon=TRUE; - - while((*nreadpset.ftp_response_timeout ) - /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine - remaining time. Also, use "now" as opposed to "conn->now" - because ftp_response_timeout is only supposed to govern - the response for any given ftp response, not for the time - from connect to the given ftp response. */ - timeout = data->set.ftp_response_timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */ - else if(data->set.timeout) - /* if timeout is requested, find out how much remaining time we have */ - timeout = data->set.timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ - else - /* Even without a requested timeout, we only wait response_time - seconds for the full response to arrive before we bail out */ - timeout = ftpc->response_time - - Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */ - - if(timeout <=0 ) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; /* already too little time */ - } - - if(!ftpc->cache) { - interval_ms = 1 * 1000; /* use 1 second timeout intervals */ - - switch (Curl_select(sockfd, CURL_SOCKET_BAD, interval_ms)) { - case -1: /* select() error, stop reading */ - result = CURLE_RECV_ERROR; - failf(data, "FTP response aborted due to select() error: %d", - Curl_sockerrno()); - break; - case 0: /* timeout */ - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - continue; /* just continue in our loop for the timeout duration */ - - default: - break; - } - } - if(CURLE_OK == result) { - /* - * This code previously didn't use the kerberos sec_read() code - * to read, but when we use Curl_read() it may do so. Do confirm - * that this is still ok and then remove this comment! - */ - if(ftpc->cache) { - /* we had data in the "cache", copy that instead of doing an actual - * read - * - * Dave Meyer, December 2003: - * ftp->cache_size is cast to int 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. - */ - memcpy(ptr, ftpc->cache, (int)ftpc->cache_size); - gotbytes = (int)ftpc->cache_size; - free(ftpc->cache); /* free the cache */ - ftpc->cache = NULL; /* clear the pointer */ - ftpc->cache_size = 0; /* zero the size just in case */ - } - else { - int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes); - if(res < 0) - /* EWOULDBLOCK */ - continue; /* go looping again */ - -#ifdef CURL_DOES_CONVERSIONS - if((res == CURLE_OK) && (gotbytes > 0)) { - /* convert from the network encoding */ - result = res = Curl_convert_from_network(data, ptr, gotbytes); - /* Curl_convert_from_network calls failf if unsuccessful */ - } -#endif /* CURL_DOES_CONVERSIONS */ - - if(CURLE_OK != res) - keepon = FALSE; - } - - if(!keepon) - ; - else if(gotbytes <= 0) { - keepon = FALSE; - result = CURLE_RECV_ERROR; - failf(data, "FTP response reading failed"); - } - 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 */ - int i; - - conn->headerbytecount += gotbytes; - - *nreadp += gotbytes; - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; - if(*ptr=='\n') { - /* a newline is CRLF in ftp-talk, so the CR is ignored as - the line isn't really terminated until the LF comes */ - - /* output debug output if that is requested */ - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - line_start, (size_t)perline, conn); - - /* - * 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(conn, CLIENTWRITE_HEADER, - line_start, perline); - if(result) - return result; - - if(perline>3 && lastline(line_start)) { - /* This is the end of the last line, copy the last - * line to the start of the buffer and zero terminate, - * for old times sake (and krb4)! */ - char *meow; - int n; - for(meow=line_start, n=0; meowcache_size = gotbytes - i; - ftpc->cache = (char *)malloc((int)ftpc->cache_size); - if(ftpc->cache) - memcpy(ftpc->cache, line_start, (int)ftpc->cache_size); - else - return CURLE_OUT_OF_MEMORY; /**BANG**/ - } - } /* there was data */ - } /* if(no error) */ - } /* while there's buffer left and loop is requested */ - - if(!result) - code = atoi(buf); - -#ifdef HAVE_KRB4 - /* handle the security-oriented responses 6xx ***/ - /* FIXME: some errorchecking perhaps... ***/ - switch(code) { - case 631: - Curl_sec_read_msg(conn, buf, prot_safe); - break; - case 632: - Curl_sec_read_msg(conn, buf, prot_private); - break; - case 633: - Curl_sec_read_msg(conn, buf, prot_confidential); - break; - default: - /* normal ftp stuff we pass through! */ - break; - } -#endif - - if(ftpcode) - *ftpcode=code; /* return the initial number like this */ - - /* store the latest code for later retrieval */ - conn->data->info.httpcode=code; - - return result; -} - -/* This is the ONLY way to change FTP state! */ -static void state(struct connectdata *conn, - ftpstate state) -{ -#ifdef CURLDEBUG - /* for debug purposes */ - const char *names[]={ - "STOP", - "WAIT220", - "AUTH", - "USER", - "PASS", - "ACCT", - "PBSZ", - "PROT", - "CCC", - "PWD", - "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", - "PASV", - "LIST", - "RETR", - "STOR", - "QUIT" - }; -#endif - struct ftp_conn *ftpc = &conn->proto.ftpc; -#ifdef CURLDEBUG - if(ftpc->state != state) - infof(conn->data, "FTP %p state change from %s to %s\n", - ftpc, names[ftpc->state], names[state]); -#endif - ftpc->state = state; -} - -static CURLcode ftp_state_user(struct connectdata *conn) -{ - CURLcode result; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - /* send USER */ - NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); - - state(conn, FTP_USER); - conn->data->state.ftp_trying_alternative = FALSE; - - return CURLE_OK; -} - -static CURLcode ftp_state_pwd(struct connectdata *conn) -{ - CURLcode result; - - /* send PWD to discover our entry point */ - NBFTPSENDF(conn, "PWD", NULL); - state(conn, FTP_PWD); - - return CURLE_OK; -} - -/* For the FTP "protocol connect" and "doing" phases only */ -int Curl_ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(!numsocks) - return GETSOCK_BLANK; - - socks[0] = conn->sock[FIRSTSOCKET]; - - if(ftpc->sendleft) { - /* write mode */ - return GETSOCK_WRITESOCK(0); - } - - /* read mode */ - return GETSOCK_READSOCK(0); -} - -/* This is called after the FTP_QUOTE state is passed. - - ftp_state_cwd() sends the range of PWD commands to the server to change to - the correct directory. It may also need to send MKD commands to create - missing ones, if that option is enabled. -*/ -static CURLcode ftp_state_cwd(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(ftpc->cwddone) - /* already done and fine */ - result = ftp_state_post_cwd(conn); - else { - ftpc->count2 = 0; - if (conn->bits.reuse && ftpc->entrypath) { - /* This is a re-used connection. Since we change directory to where the - transfer is taking place, we must first get back to the original dir - where we ended up after login: */ - ftpc->count1 = 0; /* we count this as the first path, then we add one - for all upcoming ones in the ftp->dirs[] array */ - NBFTPSENDF(conn, "CWD %s", ftpc->entrypath); - state(conn, FTP_CWD); - } - else { - if(ftpc->dirdepth) { - ftpc->count1 = 1; - /* issue the first CWD, the rest is sent when the CWD responses are - received... */ - NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]); - state(conn, FTP_CWD); - } - else { - /* No CWD necessary */ - result = ftp_state_post_cwd(conn); - } - } - } - return result; -} - -typedef enum { - EPRT, - PORT, - DONE -} ftpport; - -static CURLcode ftp_state_use_port(struct connectdata *conn, - ftpport fcmd) /* start with this */ - -{ - CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct SessionHandle *data=conn->data; - curl_socket_t portsock= CURL_SOCKET_BAD; - char myhost[256] = ""; - -#ifdef ENABLE_IPV6 - /****************************************************************** - * IPv6-specific section - */ - struct Curl_sockaddr_storage ss; - struct addrinfo *res, *ai; - socklen_t sslen; - char hbuf[NI_MAXHOST]; - struct sockaddr *sa=(struct sockaddr *)&ss; - char tmp[1024]; - const char *mode[] = { "EPRT", "PORT", NULL }; - int rc; - int error; - char *host=NULL; - struct Curl_dns_entry *h=NULL; - unsigned short port = 0; - - /* Step 1, figure out what address that is requested */ - - if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) { - /* attempt to get the address of the given interface name */ - if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf))) - /* not an interface, use the given string as host name instead */ - host = data->set.ftpport; - else - host = hbuf; /* use the hbuf for host name */ - } /* data->set.ftpport */ - - if(!host) { - /* 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], (struct sockaddr *)&ss, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, Curl_sockerrno()) ); - return CURLE_FTP_PORT_FAILED; - } - - if (sslen > (socklen_t)sizeof(ss)) - sslen = sizeof(ss); - rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, - 0, NIFLAGS); - if(rc) { - failf(data, "getnameinfo() returned %d \n", rc); - return CURLE_FTP_PORT_FAILED; - } - host = hbuf; /* use this host name */ - } - - rc = Curl_resolv(conn, host, 0, &h); - if(rc == CURLRESOLV_PENDING) - rc = Curl_wait_for_resolv(conn, &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! */ - - - /* step 2, create a socket for the requested address */ - - portsock = CURL_SOCKET_BAD; - error = 0; - for (ai = res; ai; ai = ai->ai_next) { - /* - * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype): - */ - if (ai->ai_socktype == 0) - ai->ai_socktype = conn->socktype; - - portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (portsock == CURL_SOCKET_BAD) { - error = Curl_sockerrno(); - continue; - } - break; - } - if(!ai) { - failf(data, "socket failure: %s", Curl_strerror(conn, error)); - return CURLE_FTP_PORT_FAILED; - } - - /* step 3, bind to a suitable local address */ - - /* Try binding the given address. */ - if (bind(portsock, ai->ai_addr, ai->ai_addrlen)) { - - /* It failed. Bind the address used for the control connection instead */ - sslen = sizeof(ss); - if (getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, Curl_sockerrno()) ); - sclose(portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* set port number to zero to make bind() pick "any" */ - if(((struct sockaddr *)sa)->sa_family == AF_INET) - ((struct sockaddr_in *)sa)->sin_port=0; - else - ((struct sockaddr_in6 *)sa)->sin6_port =0; - - if (sslen > (socklen_t)sizeof(ss)) - sslen = sizeof(ss); - - if(bind(portsock, (struct sockaddr *)sa, sslen)) { - failf(data, "bind failed: %s", Curl_strerror(conn, Curl_sockerrno())); - sclose(portsock); - return CURLE_FTP_PORT_FAILED; - } - } - - /* get the name again after the bind() so that we can extract the - port number it uses now */ - sslen = sizeof(ss); - if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, Curl_sockerrno()) ); - sclose(portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* step 4, listen on the socket */ - - if (listen(portsock, 1)) { - failf(data, "socket failure: %s", Curl_strerror(conn, Curl_sockerrno())); - sclose(portsock); - return CURLE_FTP_PORT_FAILED; - } - - /* step 5, send the proper FTP command */ - - /* get a plain printable version of the numerical address to work with - below */ - Curl_printable_address(ai, myhost, sizeof(myhost)); - -#ifdef PF_INET6 - 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 - - for (; fcmd != DONE; fcmd++) { - - if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) - /* if disabled, goto next */ - continue; - - switch (sa->sa_family) { - case AF_INET: - port = ntohs(((struct sockaddr_in *)sa)->sin_port); - break; - case AF_INET6: - port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); - break; - default: - break; - } - - if (EPRT == fcmd) { - /* - * Two fine examples from RFC2428; - * - * EPRT |1|132.235.1.2|6275| - * - * EPRT |2|1080::8:800:200C:417A|5282| - */ - - result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd], - ai->ai_family == AF_INET?1:2, - myhost, port); - if(result) - return result; - break; - } - else if (PORT == fcmd) { - char *source = myhost; - char *dest = tmp; - - if ((PORT == fcmd) && ai->ai_family != AF_INET) - continue; - - /* translate x.x.x.x to x,x,x,x */ - while(source && *source) { - if(*source == '.') - *dest=','; - else - *dest = *source; - dest++; - source++; - } - *dest = 0; - snprintf(dest, 20, ",%d,%d", port>>8, port&0xff); - - result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp); - if(result) - return result; - break; - } - } - - /* store which command was sent */ - ftpc->count1 = fcmd; - - /* we set the secondary socket variable to this for now, it is only so that - the cleanup function will close it in case we fail before the true - secondary stuff is made */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = portsock; - -#else - /****************************************************************** - * IPv4-specific section - */ - struct sockaddr_in sa; - unsigned short porttouse; - bool sa_filled_in = FALSE; - Curl_addrinfo *addr = NULL; - unsigned short ip[4]; - bool freeaddr = TRUE; - socklen_t sslen = sizeof(sa); - - (void)fcmd; /* not used in the IPv4 code */ - if(data->set.ftpport) { - in_addr_t in; - - /* First check if the given name is an IP address */ - in=inet_addr(data->set.ftpport); - - if(in != CURL_INADDR_NONE) - /* this is an IPv4 address */ - addr = Curl_ip2addr(in, data->set.ftpport, 0); - else { - if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) { - /* The interface to IP conversion provided a dotted address */ - in=inet_addr(myhost); - addr = Curl_ip2addr(in, myhost, 0); - } - else if(strlen(data->set.ftpport)> 1) { - /* might be a host name! */ - struct Curl_dns_entry *h=NULL; - int rc = Curl_resolv(conn, data->set.ftpport, 0, &h); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING */ - rc = Curl_wait_for_resolv(conn, &h); - if(h) { - addr = h->addr; - /* when we return from this function, we can forget about this entry - so we can unlock it now already */ - Curl_resolv_unlock(data, h); - - freeaddr = FALSE; /* make sure we don't free 'addr' in this function - since it points to a DNS cache entry! */ - } /* (h) */ - else { - infof(data, "Failed to resolve host name %s\n", data->set.ftpport); - } - } /* strlen */ - } /* CURL_INADDR_NONE */ - } /* data->set.ftpport */ - - if(!addr) { - /* pick a suitable default here */ - - if (getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)&sa, &sslen)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, Curl_sockerrno()) ); - return CURLE_FTP_PORT_FAILED; - } - if (sslen > (socklen_t)sizeof(sa)) - sslen = sizeof(sa); - - sa_filled_in = TRUE; /* the sa struct is filled in */ - } - - if (addr || sa_filled_in) { - portsock = socket(AF_INET, SOCK_STREAM, 0); - if(CURL_SOCKET_BAD != portsock) { - - /* we set the secondary socket variable to this for now, it - is only so that the cleanup function will close it in case - we fail before the true secondary stuff is made */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = portsock; - - if(!sa_filled_in) { - memcpy(&sa, addr->ai_addr, sslen); - sa.sin_addr.s_addr = INADDR_ANY; - } - - sa.sin_port = 0; - sslen = sizeof(sa); - - if(bind(portsock, (struct sockaddr *)&sa, sslen) == 0) { - /* we succeeded to bind */ - struct sockaddr_in add; - socklen_t socksize = sizeof(add); - - if(getsockname(portsock, (struct sockaddr *) &add, - &socksize)) { - failf(data, "getsockname() failed: %s", - Curl_strerror(conn, Curl_sockerrno()) ); - return CURLE_FTP_PORT_FAILED; - } - porttouse = ntohs(add.sin_port); - - if ( listen(portsock, 1) < 0 ) { - failf(data, "listen(2) failed on socket"); - return CURLE_FTP_PORT_FAILED; - } - } - else { - failf(data, "bind(2) failed on socket"); - return CURLE_FTP_PORT_FAILED; - } - } - else { - failf(data, "socket(2) failed (%s)"); - return CURLE_FTP_PORT_FAILED; - } - } - else { - failf(data, "couldn't find IP address to use"); - return CURLE_FTP_PORT_FAILED; - } - - if(sa_filled_in) - Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr, - myhost, sizeof(myhost)); - else - Curl_printable_address(addr, myhost, sizeof(myhost)); - - if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - - infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n", - ip[0], ip[1], ip[2], ip[3], porttouse); - - result=Curl_nbftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d", - ip[0], ip[1], ip[2], ip[3], - porttouse >> 8, porttouse & 255); - if(result) - return result; - } - else - return CURLE_FTP_PORT_FAILED; - - if(freeaddr) - Curl_freeaddrinfo(addr); - - ftpc->count1 = PORT; - -#endif /* end of ipv4-specific code */ - - /* this tcpconnect assignment below is a hackish work-around to make the - multi interface with active FTP work - as it will not wait for a - (passive) connect in Curl_is_connected(). - - The *proper* fix is to make sure that the active connection from the - server is done in a non-blocking way. Currently, it is still BLOCKING. - */ - conn->bits.tcpconnect = TRUE; - - state(conn, FTP_PORT); - return result; -} - -static CURLcode ftp_state_use_pasv(struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - /* - Here's the excecutive summary on what to do: - - PASV is RFC959, expect: - 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) - - LPSV is RFC1639, expect: - 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) - - EPSV is RFC2428, expect: - 229 Entering Extended Passive Mode (|||port|) - - */ - - const char *mode[] = { "EPSV", "PASV", NULL }; - int modeoff; - -#ifdef PF_INET6 - if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) - /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the - request and enable EPSV again! */ - conn->bits.ftp_use_epsv = TRUE; -#endif - - modeoff = conn->bits.ftp_use_epsv?0:1; - - result = Curl_nbftpsendf(conn, "%s", mode[modeoff]); - if(result) - return result; - - ftpc->count1 = modeoff; - state(conn, FTP_PASV); - infof(conn->data, "Connect data stream passively\n"); - - return result; -} - -/* REST is the last command in the chain of commands when a "head"-like - request is made. Thus, if an actual transfer is to be made this is where - we take off for real. */ -static CURLcode ftp_state_post_rest(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - struct SessionHandle *data = conn->data; - - if(ftp->no_transfer || conn->bits.no_body) { - /* doesn't transfer any data */ - ftp->no_transfer = TRUE; - - /* still possibly do PRE QUOTE jobs */ - state(conn, FTP_RETR_PREQUOTE); - result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); - } - else if(data->set.ftp_use_port) { - /* We have chosen to use the PORT (or similar) command */ - result = ftp_state_use_port(conn, EPRT); - } - else { - /* We have chosen (this is default) to use the PASV (or similar) command */ - result = ftp_state_use_pasv(conn); - } - return result; -} - -static CURLcode ftp_state_post_size(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - - if(ftp->no_transfer) { - /* if a "head"-like request is being made */ - - /* Determine if server can respond to REST command and therefore - whether it supports range */ - NBFTPSENDF(conn, "REST %d", 0); - - state(conn, FTP_REST); - } - else - result = ftp_state_post_rest(conn); - - return result; -} - -static CURLcode ftp_state_post_type(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - - if(ftp->no_transfer) { - /* if a "head"-like request is being made */ - - /* we know ftp->file is a valid pointer to a file name */ - NBFTPSENDF(conn, "SIZE %s", ftp->file); - - state(conn, FTP_SIZE); - } - else - result = ftp_state_post_size(conn); - - return result; -} - -static CURLcode ftp_state_post_listtype(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - /* If this output is to be machine-parsed, the NLST command might be better - to use, since the LIST command output is not specified or standard in any - way. It has turned out that the NLST list output is not the same on all - servers either... */ - - NBFTPSENDF(conn, "%s", - data->set.customrequest?data->set.customrequest: - (data->set.ftp_list_only?"NLST":"LIST")); - - state(conn, FTP_LIST); - - return result; -} - -static CURLcode ftp_state_post_retrtype(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* We've sent the TYPE, now we must send the list of prequote strings */ - - result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); - - return result; -} - -static CURLcode ftp_state_post_stortype(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - /* We've sent the TYPE, now we must send the list of prequote strings */ - - result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE); - - return result; -} - -static CURLcode ftp_state_post_mdtm(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - struct SessionHandle *data = conn->data; - - /* If we have selected NOBODY and HEADER, it means that we only want file - information. Which in FTP can't be much more than the file size and - date. */ - if(conn->bits.no_body && data->set.include_header && ftp->file && - ftp_need_type(conn, data->set.prefer_ascii)) { - /* The SIZE command is _not_ RFC 959 specified, and therefor many servers - may not support it! It is however the only way we have to get a file's - size! */ - - ftp->no_transfer = TRUE; /* this means no actual transfer will be made */ - - /* Some servers return different sizes for different modes, and thus we - must set the proper type before we check the size */ - result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE); - if (result) - return result; - } - else - result = ftp_state_post_type(conn); - - return result; -} - -/* This is called after the CWD commands have been done in the beginning of - the DO phase */ -static CURLcode ftp_state_post_cwd(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - struct SessionHandle *data = conn->data; - - /* Requested time of file or time-depended transfer? */ - if((data->set.get_filetime || data->set.timecondition) && ftp->file) { - - /* we have requested to get the modified-time of the file, this is a white - spot as the MDTM is not mentioned in RFC959 */ - NBFTPSENDF(conn, "MDTM %s", ftp->file); - - state(conn, FTP_MDTM); - } - else - result = ftp_state_post_mdtm(conn); - - return result; -} - - -/* This is called after the TYPE and possible quote commands have been sent */ -static CURLcode ftp_state_ul_setup(struct connectdata *conn, - bool sizechecked) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - struct SessionHandle *data = conn->data; - curl_off_t passed=0; - - if((data->reqdata.resume_from && !sizechecked) || - ((data->reqdata.resume_from > 0) && sizechecked)) { - /* 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 - 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 */ - /* 4. lower the infilesize counter */ - /* => transfer as usual */ - - if(data->reqdata.resume_from < 0 ) { - /* Got no given size to start from, figure it out */ - NBFTPSENDF(conn, "SIZE %s", ftp->file); - state(conn, FTP_STOR_SIZE); - return result; - } - - /* enable append */ - data->set.ftp_append = TRUE; - - /* Let's read off the proper amount of bytes from the input. If we knew it - was a proper file we could've just fseek()ed but we only have a stream - here */ - - /* TODO: allow the ioctlfunction to provide a fast forward function that - can be used here and use this method only as a fallback! */ - do { - curl_off_t readthisamountnow = (data->reqdata.resume_from - passed); - curl_off_t actuallyread; - - if(readthisamountnow > BUFSIZE) - readthisamountnow = BUFSIZE; - - actuallyread = (curl_off_t) - conn->fread(data->state.buffer, 1, (size_t)readthisamountnow, - conn->fread_in); - - passed += actuallyread; - if(actuallyread != readthisamountnow) { - failf(data, "Could only read %" FORMAT_OFF_T - " bytes from the input", passed); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed != data->reqdata.resume_from); - - /* now, decrease the size of the read */ - if(data->set.infilesize>0) { - data->set.infilesize -= data->reqdata.resume_from; - - if(data->set.infilesize <= 0) { - infof(data, "File already completely uploaded\n"); - - /* no data to transfer */ - result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - /* Set no_transfer so that we won't get any error in - * Curl_ftp_done() because we didn't transfer anything! */ - ftp->no_transfer = TRUE; - - state(conn, FTP_STOP); - return CURLE_OK; - } - } - /* we've passed, proceed as normal */ - } /* resume_from */ - - NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s", - ftp->file); - - state(conn, FTP_STOR); - - return result; -} - -static CURLcode ftp_state_quote(struct connectdata *conn, - bool init, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - bool quote=FALSE; - struct curl_slist *item; - - switch(instate) { - case FTP_QUOTE: - default: - item = data->set.quote; - break; - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - item = data->set.prequote; - break; - case FTP_POSTQUOTE: - item = data->set.postquote; - break; - } - - if(init) - ftpc->count1 = 0; - else - ftpc->count1++; - - if(item) { - int i = 0; - - /* Skip count1 items in the linked list */ - while((i< ftpc->count1) && item) { - item = item->next; - i++; - } - if(item) { - NBFTPSENDF(conn, "%s", item->data); - state(conn, instate); - quote = TRUE; - } - } - - if(!quote) { - /* No more quote to send, continue to ... */ - switch(instate) { - case FTP_QUOTE: - default: - result = ftp_state_cwd(conn); - break; - case FTP_RETR_PREQUOTE: - if (ftp->no_transfer) - state(conn, FTP_STOP); - else { - NBFTPSENDF(conn, "SIZE %s", ftp->file); - state(conn, FTP_RETR_SIZE); - } - break; - case FTP_STOR_PREQUOTE: - result = ftp_state_ul_setup(conn, FALSE); - break; - case FTP_POSTQUOTE: - break; - } - } - - return result; -} - -static CURLcode ftp_state_pasv_resp(struct connectdata *conn, - int ftpcode) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result; - struct SessionHandle *data=conn->data; - Curl_addrinfo *conninfo; - struct Curl_dns_entry *addr=NULL; - int rc; - unsigned short connectport; /* the local port connect() should use! */ - unsigned short newport=0; /* remote port */ - bool connected; - - /* newhost must be able to hold a full IP-style address in ASCII, which - in the IPv6 case means 5*8-1 = 39 letters */ -#define NEWHOST_BUFSIZE 48 - char newhost[NEWHOST_BUFSIZE]; - char *str=&data->state.buffer[4]; /* start on the first letter */ - - if((ftpc->count1 == 0) && - (ftpcode == 229)) { - /* positive EPSV response */ - char *ptr = strchr(str, '('); - if(ptr) { - unsigned int num; - char separator[4]; - ptr++; - if(5 == sscanf(ptr, "%c%c%c%u%c", - &separator[0], - &separator[1], - &separator[2], - &num, - &separator[3])) { - const char sep1 = separator[0]; - int i; - - /* The four separators should be identical, or else this is an oddly - formatted reply and we bail out immediately. */ - for(i=1; i<4; i++) { - if(separator[i] != sep1) { - ptr=NULL; /* set to NULL to signal error */ - break; - } - } - if(ptr) { - newport = num; - - if (conn->bits.tunnel_proxy) - /* proxy tunnel -> use other host info because ip_addr_str is the - proxy address not the ftp host */ - snprintf(newhost, sizeof(newhost), "%s", conn->host.name); - else - /* use the same IP we are already connected to */ - snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str); - } - } - else - ptr=NULL; - } - if(!ptr) { - failf(data, "Weirdly formatted EPSV reply"); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - } - else if((ftpc->count1 == 1) && - (ftpcode == 227)) { - /* positive PASV response */ - int ip[4]; - int port[2]; - - /* - * Scan for a sequence of six comma-separated numbers and use them as - * IP+port indicators. - * - * Found reply-strings include: - * "227 Entering Passive Mode (127,0,0,1,4,51)" - * "227 Data transfer will passively listen to 127,0,0,1,4,51" - * "227 Entering passive mode. 127,0,0,1,4,51" - */ - while(*str) { - if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d", - &ip[0], &ip[1], &ip[2], &ip[3], - &port[0], &port[1])) - break; - str++; - } - - if(!*str) { - failf(data, "Couldn't interpret the 227-response"); - return CURLE_FTP_WEIRD_227_FORMAT; - } - - /* we got OK from server */ - if(data->set.ftp_skip_ip) { - /* told to ignore the remotely given IP but instead use the one we used - for the control connection */ - infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n", - ip[0], ip[1], ip[2], ip[3], - conn->ip_addr_str); - if (conn->bits.tunnel_proxy) - /* proxy tunnel -> use other host info because ip_addr_str is the - proxy address not the ftp host */ - snprintf(newhost, sizeof(newhost), "%s", conn->host.name); - else - snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str); - } - else - snprintf(newhost, sizeof(newhost), - "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - newport = (port[0]<<8) + port[1]; - } - else if(ftpc->count1 == 0) { - /* EPSV failed, move on to PASV */ - - /* disable it for next transfer */ - conn->bits.ftp_use_epsv = FALSE; - infof(data, "disabling EPSV usage\n"); - - NBFTPSENDF(conn, "PASV", NULL); - ftpc->count1++; - /* remain in the FTP_PASV state */ - return result; - } - else { - failf(data, "Bad PASV/EPSV response: %03d", ftpcode); - return CURLE_FTP_WEIRD_PASV_REPLY; - } - - if(data->set.proxy && *data->set.proxy) { - /* - * This is a tunnel through a http proxy and we need to connect to the - * proxy again 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! - */ - rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING */ - rc = Curl_wait_for_resolv(conn, &addr); - - connectport = - (unsigned short)conn->port; /* we connect to the proxy's port */ - - } - else { - /* normal, direct, ftp connection */ - rc = Curl_resolv(conn, newhost, newport, &addr); - if(rc == CURLRESOLV_PENDING) - /* BLOCKING */ - rc = Curl_wait_for_resolv(conn, &addr); - - if(!addr) { - failf(data, "Can't resolve new host %s:%d", newhost, newport); - return CURLE_FTP_CANT_GET_HOST; - } - connectport = newport; /* we connect to the remote port */ - } - - result = Curl_connecthost(conn, - addr, - &conn->sock[SECONDARYSOCKET], - &conninfo, - &connected); - - Curl_resolv_unlock(data, addr); /* we're done using this address */ - - if (result && ftpc->count1 == 0 && ftpcode == 229) { - infof(data, "got positive EPSV response, but can't connect. " - "Disabling EPSV\n"); - /* disable it for next transfer */ - conn->bits.ftp_use_epsv = FALSE; - data->state.errorbuf = FALSE; /* allow error message to get rewritten */ - NBFTPSENDF(conn, "PASV", NULL); - ftpc->count1++; - /* remain in the FTP_PASV state */ - return result; - } - - if(result) - return result; - - conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */ - - /* - * When this is used from the multi interface, this might've returned with - * the 'connected' set to FALSE and thus we are now awaiting a non-blocking - * connect to connect and we should not be "hanging" here waiting. - */ - - if(data->set.verbose) - /* this just dumps information about this second connection */ - ftp_pasv_verbose(conn, conninfo, newhost, connectport); - -#ifndef CURL_DISABLE_HTTP - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* FIX: this MUST wait for a proper connect first if 'connected' is - * FALSE */ - - /* BLOCKING */ - /* We want "seamless" FTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want FTP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * FTP pointer - */ - struct HTTP http_proxy; - struct FTP *ftp_save = data->reqdata.proto.ftp; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->reqdata.proto.http = &http_proxy; - - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport); - - data->reqdata.proto.ftp = ftp_save; - - if(CURLE_OK != result) - return result; - } -#endif /* CURL_DISABLE_HTTP */ - - state(conn, FTP_STOP); /* this phase is completed */ - - return result; -} - -static CURLcode ftp_state_port_resp(struct connectdata *conn, - int ftpcode) -{ - struct SessionHandle *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - ftpport fcmd = (ftpport)ftpc->count1; - CURLcode result = CURLE_OK; - - if(ftpcode != 200) { - /* the command failed */ - - if (EPRT == fcmd) { - infof(data, "disabling EPRT usage\n"); - conn->bits.ftp_use_eprt = FALSE; - } - fcmd++; - - if(fcmd == DONE) { - failf(data, "Failed to do PORT"); - result = CURLE_FTP_PORT_FAILED; - } - else - /* try next */ - result = ftp_state_use_port(conn, fcmd); - } - else { - infof(data, "Connect data stream actively\n"); - state(conn, FTP_STOP); /* end of DO phase */ - } - - return result; -} - -static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, - int ftpcode) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - - switch(ftpcode) { - case 213: - { - /* 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; - char *buf = data->state.buffer; - if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d", - &year, &month, &day, &hour, &minute, &second)) { - /* we have a time, reformat it */ - time_t secs=time(NULL); - /* using the good old yacc/bison yuck */ - snprintf(buf, sizeof(conn->data->state.buffer), - "%04d%02d%02d %02d:%02d:%02d GMT", - year, month, day, hour, minute, second); - /* now, convert this into a time() value: */ - data->info.filetime = (long)curl_getdate(buf, &secs); - } - - /* If we asked for a time of the file and we actually got one as well, - we "emulate" a HTTP-style header in our output. */ - - if(conn->bits.no_body && - data->set.include_header && - ftp->file && - data->set.get_filetime && - (data->info.filetime>=0) ) { - struct tm *tm; - time_t clock = (time_t)data->info.filetime; -#ifdef HAVE_GMTIME_R - struct tm buffer; - tm = (struct tm *)gmtime_r(&clock, &buffer); -#else - tm = gmtime(&clock); -#endif - /* format: "Tue, 15 Nov 1994 12:45:26" */ - snprintf(buf, BUFSIZE-1, - "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); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - if(result) - return result; - } /* end of a ridiculous amount of conditionals */ - } - break; - default: - infof(data, "unsupported MDTM reply format\n"); - break; - case 550: /* "No such file or directory" */ - failf(data, "Given file does not exist"); - result = CURLE_FTP_COULDNT_RETR_FILE; - break; - } - - if(data->set.timecondition) { - if((data->info.filetime > 0) && (data->set.timevalue > 0)) { - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - if(data->info.filetime <= data->set.timevalue) { - infof(data, "The requested document is not new enough\n"); - ftp->no_transfer = TRUE; /* mark this to not transfer data */ - state(conn, FTP_STOP); - return CURLE_OK; - } - break; - case CURL_TIMECOND_IFUNMODSINCE: - if(data->info.filetime > data->set.timevalue) { - infof(data, "The requested document is not old enough\n"); - ftp->no_transfer = TRUE; /* mark this to not transfer data */ - state(conn, FTP_STOP); - return CURLE_OK; - } - break; - } /* switch */ - } - else { - infof(data, "Skipping time comparison\n"); - } - } - - if(!result) - result = ftp_state_post_mdtm(conn); - - return result; -} - -static CURLcode ftp_state_type_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; - - if(ftpcode/100 != 2) { - /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a - successful 'TYPE I'. While that is not as RFC959 says, it is still a - positive response code and we allow that. */ - failf(data, "Couldn't set desired mode"); - return CURLE_FTP_COULDNT_SET_BINARY; /* FIX */ - } - if(ftpcode != 200) - infof(data, "Got a %03d response code instead of the assumed 200\n", - ftpcode); - - if(instate == FTP_TYPE) - result = ftp_state_post_type(conn); - else if(instate == FTP_LIST_TYPE) - result = ftp_state_post_listtype(conn); - else if(instate == FTP_RETR_TYPE) - result = ftp_state_post_retrtype(conn); - else if(instate == FTP_STOR_TYPE) - result = ftp_state_post_stortype(conn); - - return result; -} - -static CURLcode ftp_state_post_retr_size(struct connectdata *conn, - curl_off_t filesize) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - - if (data->set.max_filesize && (filesize > data->set.max_filesize)) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - ftp->downloadsize = filesize; - - if(data->reqdata.resume_from) { - /* 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 doesn't support SIZE\n"); - /* 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 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->reqdata.resume_from< 0) { - /* We're supposed to download the last abs(from) bytes */ - if(filesize < -data->reqdata.resume_from) { - failf(data, "Offset (%" FORMAT_OFF_T - ") was beyond file size (%" FORMAT_OFF_T ")", - data->reqdata.resume_from, filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* convert to size to download */ - ftp->downloadsize = -data->reqdata.resume_from; - /* download from where? */ - data->reqdata.resume_from = filesize - ftp->downloadsize; - } - else { - if(filesize < data->reqdata.resume_from) { - failf(data, "Offset (%" FORMAT_OFF_T - ") was beyond file size (%" FORMAT_OFF_T ")", - data->reqdata.resume_from, filesize); - return CURLE_BAD_DOWNLOAD_RESUME; - } - /* Now store the number of bytes we are expected to download */ - ftp->downloadsize = filesize-data->reqdata.resume_from; - } - } - - if(ftp->downloadsize == 0) { - /* no data to transfer */ - result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - infof(data, "File already completely downloaded\n"); - - /* Set no_transfer so that we won't get any error in Curl_ftp_done() - * because we didn't transfer the any file */ - ftp->no_transfer = TRUE; - state(conn, FTP_STOP); - return CURLE_OK; - } - - /* Set resume file transfer offset */ - infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T - "\n", data->reqdata.resume_from); - - NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->reqdata.resume_from); - - state(conn, FTP_RETR_REST); - - } - else { - /* no resume */ - NBFTPSENDF(conn, "RETR %s", ftp->file); - state(conn, FTP_RETR); - } - - return result; -} - -static CURLcode ftp_state_size_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; - curl_off_t filesize; - char *buf = data->state.buffer; - - /* get the size from the ascii string: */ - filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1; - - if(instate == FTP_SIZE) { - if(-1 != filesize) { - snprintf(buf, sizeof(data->state.buffer), - "Content-Length: %" FORMAT_OFF_T "\r\n", filesize); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - if(result) - return result; - } - result = ftp_state_post_size(conn); - } - else if(instate == FTP_RETR_SIZE) - result = ftp_state_post_retr_size(conn, filesize); - else if(instate == FTP_STOR_SIZE) { - data->reqdata.resume_from = filesize; - result = ftp_state_ul_setup(conn, TRUE); - } - - return result; -} - -static CURLcode ftp_state_rest_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - - switch(instate) { - case FTP_REST: - default: - if (ftpcode == 350) { - result = Curl_client_write(conn, CLIENTWRITE_BOTH, - (char *)"Accept-ranges: bytes\r\n", 0); - if(result) - return result; - } - - result = ftp_state_post_rest(conn); - break; - - case FTP_RETR_REST: - if (ftpcode != 350) { - failf(conn->data, "Couldn't use REST"); - result = CURLE_FTP_COULDNT_USE_REST; - } - else { - NBFTPSENDF(conn, "RETR %s", ftp->file); - state(conn, FTP_RETR); - } - break; - } - - return result; -} - -static CURLcode ftp_state_stor_resp(struct connectdata *conn, - int ftpcode) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - - if(ftpcode>=400) { - failf(data, "Failed FTP upload: %0d", ftpcode); - /* oops, we never close the sockets! */ - return CURLE_FTP_COULDNT_STOR_FILE; - } - - if(data->set.ftp_use_port) { - /* BLOCKING */ - /* PORT means we are now awaiting the server to connect to us. */ - result = AllowServerConnect(conn); - if( result ) - return result; - } - - if(conn->ssl[SECONDARYSOCKET].use) { - /* since we only have a plaintext TCP connection here, we must now - do the TLS stuff */ - infof(data, "Doing the SSL/TLS handshake on the data stream\n"); - /* BLOCKING */ - result = Curl_ssl_connect(conn, SECONDARYSOCKET); - if(result) - return result; - } - - *(ftp->bytecountp)=0; - - /* When we know we're uploading a specified file, we can get the file - size prior to the actual upload. */ - - Curl_pgrsSetUploadSize(data, data->set.infilesize); - - result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - SECONDARYSOCKET, ftp->bytecountp); - state(conn, FTP_STOP); - - return result; -} - -/* for LIST and RETR responses */ -static CURLcode ftp_state_get_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - char *buf = data->state.buffer; - - if((ftpcode == 150) || (ftpcode == 125)) { - - /* - A; - 150 Opening BINARY mode data connection for /etc/passwd (2241 - bytes). (ok, the file is being transfered) - - B: - 150 Opening ASCII mode data connection for /bin/ls - - C: - 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). - - D: - 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes). - - E: - 125 Data connection already open; Transfer starting. */ - - curl_off_t size=-1; /* default unknown size */ - - - /* - * It appears that there are FTP-servers that return size 0 for files when - * SIZE is used on the file while being in BINARY mode. To work around - * that (stupid) behavior, we attempt to parse the RETR response even if - * the SIZE returned size zero. - * - * Debugging help from Salvatore Sorrentino on February 26, 2003. - */ - - if((instate != FTP_LIST) && - !data->set.prefer_ascii && - (ftp->downloadsize < 1)) { - /* - * 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 transfered 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; - bytes=strstr(buf, " bytes"); - if(bytes--) { - long in=(long)(bytes-buf); - /* this is a hint there is size information in there! ;-) */ - while(--in) { - /* scan for the left parenthesis and break there */ - if('(' == *bytes) - break; - /* skip only digits */ - if(!ISDIGIT(*bytes)) { - bytes=NULL; - break; - } - /* one more estep backwards */ - bytes--; - } - /* if we have nothing but digits: */ - if(bytes++) { - /* get the number! */ - size = curlx_strtoofft(bytes, NULL, 0); - } - } - } - else if(ftp->downloadsize > -1) - size = ftp->downloadsize; - - if(data->set.ftp_use_port) { - /* BLOCKING */ - result = AllowServerConnect(conn); - if( result ) - return result; - } - - if(conn->ssl[SECONDARYSOCKET].use) { - /* since we only have a plaintext TCP connection here, we must now - do the TLS stuff */ - infof(data, "Doing the SSL/TLS handshake on the data stream\n"); - result = Curl_ssl_connect(conn, SECONDARYSOCKET); - if(result) - return result; - } - - if(size > data->reqdata.maxdownload && data->reqdata.maxdownload > 0) - size = data->reqdata.size = data->reqdata.maxdownload; - - infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->reqdata.maxdownload); - - if(instate != FTP_LIST) - infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size); - - /* FTP download: */ - result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE, - ftp->bytecountp, - -1, NULL); /* no upload here */ - if(result) - return result; - - state(conn, FTP_STOP); - } - else { - if((instate == FTP_LIST) && (ftpcode == 450)) { - /* simply no matching files in the dir listing */ - ftp->no_transfer = TRUE; /* don't download anything */ - state(conn, FTP_STOP); /* this phase is over */ - } - else { - failf(data, "RETR response: %03d", ftpcode); - return CURLE_FTP_COULDNT_RETR_FILE; - } - } - - return result; -} - -/* after USER, PASS and ACCT */ -static CURLcode ftp_state_loggedin(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - -#ifdef HAVE_KRB4 - if(conn->data->set.krb4) { - /* We are logged in, asked to use Kerberos. Set the requested - * protection level - */ - if(conn->sec_complete) - /* BLOCKING */ - Curl_sec_set_protection_level(conn); - - /* We may need to issue a KAUTH here to have access to the files - * do it if user supplied a password - */ - if(conn->passwd && *conn->passwd) { - /* BLOCKING */ - result = Curl_krb_kauth(conn); - if(result) - return result; - } - } -#endif - if(conn->ssl[FIRSTSOCKET].use) { - /* PBSZ = PROTECTION BUFFER SIZE. - - The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: - - Specifically, the PROT command MUST be preceded by a PBSZ - command and a PBSZ command MUST be preceded by a successful - security data exchange (the TLS negotiation in this case) - - ... (and on page 8): - - Thus the PBSZ command must still be issued, but must have a - parameter of '0' to indicate that no buffering is taking place - and the data connection should not be encapsulated. - */ - NBFTPSENDF(conn, "PBSZ %d", 0); - state(conn, FTP_PBSZ); - } - else { - result = ftp_state_pwd(conn); - } - return result; -} - -/* for USER and PASS responses */ -static CURLcode ftp_state_user_resp(struct connectdata *conn, - int ftpcode, - ftpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - (void)instate; /* no use for this yet */ - - if((ftpcode == 331) && (ftpc->state == FTP_USER)) { - /* 331 Password required for ... - (the server requires to send the user's password too) */ - NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:""); - state(conn, FTP_PASS); - } - else if(ftpcode/100 == 2) { - /* 230 User ... logged in. - (the user logged in with or without password) */ - result = ftp_state_loggedin(conn); - } - else if(ftpcode == 332) { - if(data->set.ftp_account) { - NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account); - state(conn, FTP_ACCT); - } - else { - failf(data, "ACCT requested but none available"); - result = CURLE_LOGIN_DENIED; - } - } - else { - /* All other response codes, like: - - 530 User ... access denied - (the server denies to log the specified user) */ - - if (conn->data->set.ftp_alternative_to_user && - !conn->data->state.ftp_trying_alternative) { - /* Ok, USER failed. Let's try the supplied command. */ - NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user); - conn->data->state.ftp_trying_alternative = TRUE; - state(conn, FTP_USER); - result = CURLE_OK; - } - else { - failf(data, "Access denied: %03d", ftpcode); - result = CURLE_LOGIN_DENIED; - } - } - return result; -} - -/* for ACCT response */ -static CURLcode ftp_state_acct_resp(struct connectdata *conn, - int ftpcode) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - if(ftpcode != 230) { - failf(data, "ACCT rejected by server: %03d", ftpcode); - result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ - } - else - result = ftp_state_loggedin(conn); - - return result; -} - - -static CURLcode ftp_statemach_act(struct connectdata *conn) -{ - CURLcode result; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; - int ftpcode; - struct ftp_conn *ftpc = &conn->proto.ftpc; - static const char * const ftpauth[] = { - "SSL", "TLS" - }; - size_t nread = 0; - - if(ftpc->sendleft) { - /* we have a piece of a command still left to send */ - ssize_t written; - result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize - - ftpc->sendleft, ftpc->sendleft, &written); - if(result) - return result; - - if(written != (ssize_t)ftpc->sendleft) { - /* only a fraction was sent */ - ftpc->sendleft -= written; - } - else { - free(ftpc->sendthis); - ftpc->sendthis=NULL; - ftpc->sendleft = ftpc->sendsize = 0; - ftpc->response = Curl_tvnow(); - } - return CURLE_OK; - } - - /* we read a piece of response */ - result = ftp_readresp(sock, conn, &ftpcode, &nread); - if(result) - return result; - - if(ftpcode) { - /* we have now received a full FTP server response */ - switch(ftpc->state) { - case FTP_WAIT220: - if(ftpcode != 220) { - failf(data, "This doesn't seem like a nice ftp-server response"); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - /* We have received a 220 response fine, now we proceed. */ -#ifdef HAVE_KRB4 - if(data->set.krb4) { - /* If not anonymous login, try a secure login. Note that this - procedure is still BLOCKING. */ - - Curl_sec_request_prot(conn, "private"); - /* We set private first as default, in case the line below fails to - set a valid level */ - Curl_sec_request_prot(conn, data->set.krb4_level); - - if(Curl_sec_login(conn) != 0) - infof(data, "Logging in with password in cleartext!\n"); - else - infof(data, "Authentication successful\n"); - } -#endif - - if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but FTPS is - requested. Try a FTPS connection now */ - - ftpc->count3=0; - switch(data->set.ftpsslauth) { - case CURLFTPAUTH_DEFAULT: - case CURLFTPAUTH_SSL: - ftpc->count2 = 1; /* add one to get next */ - ftpc->count1 = 0; - break; - case CURLFTPAUTH_TLS: - ftpc->count2 = -1; /* subtract one to get next */ - ftpc->count1 = 1; - break; - default: - failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n", - data->set.ftpsslauth); - return CURLE_FAILED_INIT; /* we don't know what to do */ - } - NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]); - state(conn, FTP_AUTH); - } - else { - result = ftp_state_user(conn); - if(result) - return result; - } - - break; - - case FTP_AUTH: - /* we have gotten the response to a previous AUTH command */ - - /* RFC2228 (page 5) says: - * - * If the server is willing to accept the named security mechanism, - * and does not require any security data, it must respond with - * reply code 234/334. - */ - - if((ftpcode == 234) || (ftpcode == 334)) { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { - conn->protocol |= PROT_FTPS; - conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ - result = ftp_state_user(conn); - } - } - else if(ftpc->count3 < 1) { - ftpc->count3++; - ftpc->count1 += ftpc->count2; /* get next attempt */ - result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]); - /* remain in this same state */ - } - else { - if(data->set.ftp_ssl > CURLFTPSSL_TRY) - /* we failed and CURLFTPSSL_CONTROL or CURLFTPSSL_ALL is set */ - result = CURLE_FTP_SSL_FAILED; - else - /* ignore the failure and continue */ - result = ftp_state_user(conn); - } - - if(result) - return result; - break; - - case FTP_USER: - case FTP_PASS: - result = ftp_state_user_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_ACCT: - result = ftp_state_acct_resp(conn, ftpcode); - break; - - case FTP_PBSZ: - /* FIX: check response code */ - - /* For TLS, the data connection can have one of two security levels. - - 1) Clear (requested by 'PROT C') - - 2)Private (requested by 'PROT P') - */ - if(!conn->ssl[SECONDARYSOCKET].use) { - NBFTPSENDF(conn, "PROT %c", - data->set.ftp_ssl == CURLFTPSSL_CONTROL ? 'C' : 'P'); - state(conn, FTP_PROT); - } - else { - result = ftp_state_pwd(conn); - if(result) - return result; - } - - break; - - case FTP_PROT: - if(ftpcode/100 == 2) - /* We have enabled SSL for the data connection! */ - conn->ssl[SECONDARYSOCKET].use = - (bool)(data->set.ftp_ssl != CURLFTPSSL_CONTROL); - /* FTP servers typically responds with 500 if they decide to reject - our 'P' request */ - else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL) - /* we failed and bails out */ - return CURLE_FTP_SSL_FAILED; - - if(data->set.ftp_use_ccc) { - /* CCC - Clear Command Channel - */ - NBFTPSENDF(conn, "CCC", NULL); - state(conn, FTP_CCC); - } - else { - result = ftp_state_pwd(conn); - if(result) - return result; - } - break; - - case FTP_CCC: - if (ftpcode < 500) { - /* First shut down the SSL layer (note: this call will block) */ - result = Curl_ssl_shutdown(conn, FIRSTSOCKET); - - if(result) { - failf(conn->data, "Failed to clear the command channel (CCC)"); - return result; - } - } - - /* Then continue as normal */ - result = ftp_state_pwd(conn); - if(result) - return result; - break; - - case FTP_PWD: - if(ftpcode == 257) { - char *dir = (char *)malloc(nread+1); - char *store=dir; - char *ptr=&data->state.buffer[4]; /* start on the first letter */ - - if(!dir) - return CURLE_OUT_OF_MEMORY; - - /* Reply format is like - 257"" and the RFC959 - says - - The directory name can contain any character; embedded - double-quotes should be escaped by double-quotes (the - "quote-doubling" convention). - */ - if('\"' == *ptr) { - /* it started good */ - ptr++; - while(ptr && *ptr) { - if('\"' == *ptr) { - if('\"' == ptr[1]) { - /* "quote-doubling" */ - *store = ptr[1]; - ptr++; - } - else { - /* end of path */ - *store = '\0'; /* zero terminate */ - break; /* get out of this loop */ - } - } - else - *store = *ptr; - store++; - ptr++; - } - ftpc->entrypath =dir; /* remember this */ - infof(data, "Entry path is '%s'\n", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; - } - else { - /* couldn't get the path */ - free(dir); - infof(data, "Failed to figure out path\n"); - } - } - state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ - DEBUGF(infof(data, "protocol connect phase DONE\n")); - break; - - case FTP_QUOTE: - case FTP_POSTQUOTE: - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - if(ftpcode >= 400) { - failf(conn->data, "QUOT command failed with %03d", ftpcode); - return CURLE_FTP_QUOTE_ERROR; - } - result = ftp_state_quote(conn, FALSE, ftpc->state); - if(result) - return result; - - break; - - case FTP_CWD: - if(ftpcode/100 != 2) { - /* failure to CWD there */ - if(conn->data->set.ftp_create_missing_dirs && - ftpc->count1 && !ftpc->count2) { - /* try making it */ - ftpc->count2++; /* counter to prevent CWD-MKD loops */ - NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]); - state(conn, FTP_MKD); - } - else { - /* return failure */ - failf(data, "Server denied you to change to the given directory"); - ftpc->cwdfail = TRUE; /* don't remember this path as we failed - to enter it */ - return CURLE_FTP_ACCESS_DENIED; - } - } - else { - /* success */ - ftpc->count2=0; - if(++ftpc->count1 <= ftpc->dirdepth) { - /* send next CWD */ - NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); - } - else { - result = ftp_state_post_cwd(conn); - if(result) - return result; - } - } - break; - - case FTP_MKD: - if(ftpcode/100 != 2) { - /* failure to MKD the dir */ - failf(data, "Failed to MKD dir: %03d", ftpcode); - return CURLE_FTP_ACCESS_DENIED; - } - state(conn, FTP_CWD); - /* send CWD */ - NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); - break; - - case FTP_MDTM: - result = ftp_state_mdtm_resp(conn, ftpcode); - break; - - case FTP_TYPE: - case FTP_LIST_TYPE: - case FTP_RETR_TYPE: - case FTP_STOR_TYPE: - result = ftp_state_type_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_SIZE: - case FTP_RETR_SIZE: - case FTP_STOR_SIZE: - result = ftp_state_size_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_REST: - case FTP_RETR_REST: - result = ftp_state_rest_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_PASV: - result = ftp_state_pasv_resp(conn, ftpcode); - break; - - case FTP_PORT: - result = ftp_state_port_resp(conn, ftpcode); - break; - - case FTP_LIST: - case FTP_RETR: - result = ftp_state_get_resp(conn, ftpcode, ftpc->state); - break; - - case FTP_STOR: - result = ftp_state_stor_resp(conn, ftpcode); - break; - - case FTP_QUIT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(conn, FTP_STOP); - break; - } - } /* if(ftpcode) */ - - return result; -} - -/* Returns timeout in ms. 0 or negative number means the timeout has already - triggered */ -static long ftp_state_timeout(struct connectdata *conn) -{ - struct SessionHandle *data=conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - long timeout_ms=360000; /* in milliseconds */ - - if(data->set.ftp_response_timeout ) - /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining - time. Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed - to govern the response for any given ftp response, not for the time - from connect to the given ftp response. */ - timeout_ms = data->set.ftp_response_timeout*1000 - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */ - else if(data->set.timeout) - /* if timeout is requested, find out how much remaining time we have */ - timeout_ms = data->set.timeout*1000 - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ - else - /* Without a requested timeout, we only wait 'response_time' seconds for - the full response to arrive before we bail out */ - timeout_ms = ftpc->response_time*1000 - - Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */ - - return timeout_ms; -} - - -/* called repeatedly until done from multi.c */ -CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, - bool *done) -{ - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - struct SessionHandle *data=conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - long timeout_ms = ftp_state_timeout(conn); - - *done = FALSE; /* default to not done yet */ - - if(timeout_ms <= 0) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - rc = Curl_select(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - 0); - - if(rc == -1) { - failf(data, "select error"); - return CURLE_OUT_OF_MEMORY; - } - else if(rc != 0) { - result = ftp_statemach_act(conn); - *done = (bool)(ftpc->state == FTP_STOP); - } - /* if rc == 0, then select() timed out */ - - return result; -} - -static CURLcode ftp_easy_statemach(struct connectdata *conn) -{ - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - struct SessionHandle *data=conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - - while(ftpc->state != FTP_STOP) { - long timeout_ms = ftp_state_timeout(conn); - - if(timeout_ms <=0 ) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; /* already too little time */ - } - - rc = Curl_select(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - (int)timeout_ms); - - if(rc == -1) { - failf(data, "select error"); - return CURLE_OUT_OF_MEMORY; - } - else if(rc == 0) { - result = CURLE_OPERATION_TIMEDOUT; - break; - } - else { - result = ftp_statemach_act(conn); - if(result) - break; - } - } - - return result; -} - -/* - * Allocate and initialize the struct FTP for the current SessionHandle. If - * need be. - */ -static CURLcode ftp_init(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - struct FTP *ftp; - if(data->reqdata.proto.ftp) - return CURLE_OK; - - ftp = (struct FTP *)calloc(sizeof(struct FTP), 1); - if(!ftp) - return CURLE_OUT_OF_MEMORY; - - data->reqdata.proto.ftp = ftp; - - /* get some initial data into the ftp struct */ - ftp->bytecountp = &data->reqdata.keep.bytecount; - - /* no need to duplicate them, this connectdata struct won't change */ - ftp->user = conn->user; - ftp->passwd = conn->passwd; - if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd)) - return CURLE_URL_MALFORMAT; - - return CURLE_OK; -} - -/* - * Curl_ftp_connect() should do everything that is to be considered a part of - * the connection phase. - * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. - */ -CURLcode Curl_ftp_connect(struct connectdata *conn, - bool *done) /* see description above */ -{ - CURLcode result; -#ifndef CURL_DISABLE_HTTP - /* for FTP over HTTP proxy */ - struct HTTP http_proxy; - struct FTP *ftp_save; -#endif /* CURL_DISABLE_HTTP */ - struct ftp_conn *ftpc = &conn->proto.ftpc; - struct SessionHandle *data=conn->data; - - *done = FALSE; /* default to not done yet */ - - if (data->reqdata.proto.ftp) { - Curl_ftp_disconnect(conn); - free(data->reqdata.proto.ftp); - data->reqdata.proto.ftp = NULL; - } - - result = ftp_init(conn); - if(result) - return result; - - /* We always support persistant connections on ftp */ - conn->bits.close = FALSE; - - ftpc->response_time = 3600; /* set default response time-out */ - -#ifndef CURL_DISABLE_HTTP - if (conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* BLOCKING */ - /* We want "seamless" FTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want FTP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * FTP pointer - */ - ftp_save = data->reqdata.proto.ftp; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->reqdata.proto.http = &http_proxy; - - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->reqdata.proto.ftp = ftp_save; - - if(CURLE_OK != result) - return result; - } -#endif /* CURL_DISABLE_HTTP */ - - if(conn->protocol & PROT_FTPS) { - /* BLOCKING */ - /* FTPS is simply ftp with SSL for the control channel */ - /* now, perform the SSL initialization for this socket */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - } - - /* When we connect, we start in the state where we await the 220 - response */ - ftp_respinit(conn); /* init the response reader stuff */ - state(conn, FTP_WAIT220); - ftpc->response = Curl_tvnow(); /* start response time-out now! */ - - if(data->state.used_interface == Curl_if_multi) - result = Curl_ftp_multi_statemach(conn, done); - else { - result = ftp_easy_statemach(conn); - if(!result) - *done = TRUE; - } - - return result; -} - -/*********************************************************************** - * - * Curl_ftp_done() - * - * The DONE function. This does what needs to be done after a single DO has - * performed. - * - * Input argument is already checked for validity. - */ -CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature) -{ - struct SessionHandle *data = conn->data; - struct FTP *ftp = data->reqdata.proto.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - ssize_t nread; - int ftpcode; - CURLcode result=CURLE_OK; - bool was_ctl_valid = ftpc->ctl_valid; - size_t flen; - size_t dlen; - char *path; - char *path_to_use = data->reqdata.path; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - - if(!ftp) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the ftp struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no ftp pointer is set. - */ - return CURLE_OK; - - switch(status) { - case CURLE_BAD_DOWNLOAD_RESUME: - case CURLE_FTP_WEIRD_PASV_REPLY: - case CURLE_FTP_PORT_FAILED: - case CURLE_FTP_COULDNT_SET_BINARY: - case CURLE_FTP_COULDNT_RETR_FILE: - case CURLE_FTP_COULDNT_STOR_FILE: - case CURLE_FTP_ACCESS_DENIED: - /* the connection stays alive fine even though this happened */ - /* fall-through */ - case CURLE_OK: /* doesn't affect the control connection's status */ - if (!premature) { - ftpc->ctl_valid = was_ctl_valid; - break; - } - /* until we cope better with prematurely ended requests, let them - * fallback as if in complete failure */ - default: /* by default, an error means the control connection is - wedged and should not be used anymore */ - ftpc->ctl_valid = FALSE; - ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the - current path, as this connection is going */ - conn->bits.close = TRUE; /* marked for closure */ - break; - } - - /* now store a copy of the directory we are in */ - if(ftpc->prevpath) - free(ftpc->prevpath); - - /* get the "raw" path */ - path = curl_easy_unescape(data, path_to_use, 0, NULL); - if(!path) - return CURLE_OUT_OF_MEMORY; - - flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */ - dlen = strlen(path)-flen; - if(dlen && !ftpc->cwdfail) { - ftpc->prevpath = path; - if(flen) - /* if 'path' is not the whole string */ - ftpc->prevpath[dlen]=0; /* terminate */ - infof(data, "Remembering we are in dir %s\n", ftpc->prevpath); - } - else { - ftpc->prevpath = NULL; /* no path */ - free(path); - } - /* free the dir tree and file parts */ - freedirs(conn); - -#ifdef HAVE_KRB4 - Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]); -#endif - - /* shut down the socket to inform the server we're done */ - -#ifdef _WIN32_WCE - shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */ -#endif - - sclose(conn->sock[SECONDARYSOCKET]); - - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - - if(!ftp->no_transfer && !status && !premature) { - /* - * Let's see what the server says about the transfer we just performed, - * but lower the timeout as sometimes this connection has died while the - * data has been transfered. This happens when doing through NATs etc that - * abandon old silent connections. - */ - long old_time = ftpc->response_time; - - ftpc->response_time = 60; /* give it only a minute for now */ - - result = Curl_GetFTPResponse(&nread, conn, &ftpcode); - - ftpc->response_time = old_time; /* set this back to previous value */ - - if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { - failf(data, "control connection looks dead"); - ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - return result; - } - - if(result) - return result; - - if(!ftpc->dont_check) { - /* 226 Transfer complete, 250 Requested file action okay, completed. */ - if((ftpcode != 226) && (ftpcode != 250)) { - failf(data, "server did not report OK, got %d", ftpcode); - result = CURLE_PARTIAL_FILE; - } - } - } - - if(result || premature) - /* the response code from the transfer showed an error already so no - use checking further */ - ; - else if(data->set.upload) { - if((-1 != data->set.infilesize) && - (data->set.infilesize != *ftp->bytecountp) && - !data->set.crlf && - !ftp->no_transfer) { - failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T - " out of %" FORMAT_OFF_T " bytes)", - *ftp->bytecountp, data->set.infilesize); - result = CURLE_PARTIAL_FILE; - } - } - else { - if((-1 != k->size) && (k->size != *ftp->bytecountp) && -#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->size + data->state.crlf_conversions) != *ftp->bytecountp) && -#endif /* CURL_DO_LINEEND_CONV */ - (k->maxdownload != *ftp->bytecountp)) { - failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes", - *ftp->bytecountp); - result = CURLE_PARTIAL_FILE; - } - else if(!ftpc->dont_check && - !*ftp->bytecountp && - (k->size>0)) { - failf(data, "No data was received!"); - result = CURLE_FTP_COULDNT_RETR_FILE; - } - } - - /* clear these for next connection */ - ftp->no_transfer = FALSE; - ftpc->dont_check = FALSE; - - /* Send any post-transfer QUOTE strings? */ - if(!status && !result && !premature && data->set.postquote) - result = ftp_sendquote(conn, data->set.postquote); - - return result; -} - -/*********************************************************************** - * - * ftp_sendquote() - * - * Where a 'quote' means a list of custom commands to send to the server. - * The quote list is passed as an argument. - */ - -static -CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) -{ - struct curl_slist *item; - ssize_t nread; - int ftpcode; - CURLcode result; - - item = quote; - while (item) { - if (item->data) { - FTPSENDF(conn, "%s", item->data); - - result = Curl_GetFTPResponse(&nread, conn, &ftpcode); - if (result) - return result; - - if (ftpcode >= 400) { - failf(conn->data, "QUOT string not accepted: %s", item->data); - return CURLE_FTP_QUOTE_ERROR; - } - } - - item = item->next; - } - - return CURLE_OK; -} - -/*********************************************************************** - * - * ftp_need_type() - * - * Returns TRUE if we in the current situation should send TYPE - */ -static int ftp_need_type(struct connectdata *conn, - bool ascii_wanted) -{ - return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); -} - -/*********************************************************************** - * - * ftp_nb_type() - * - * Set TYPE. We only deal with ASCII or BINARY so this function - * sets one of them. - * If the transfer type is not sent, simulate on OK response in newstate - */ -static CURLcode ftp_nb_type(struct connectdata *conn, - bool ascii, ftpstate newstate) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result; - int want = ascii?'A':'I'; - - if (ftpc->transfertype == want) { - state(conn, newstate); - return ftp_state_type_resp(conn, 200, newstate); - } - - NBFTPSENDF(conn, "TYPE %c", want); - state(conn, newstate); - - /* keep track of our current transfer type */ - ftpc->transfertype = want; - return CURLE_OK; -} - -/*************************************************************************** - * - * ftp_pasv_verbose() - * - * This function only outputs some informationals about this second connection - * when we've issued a PASV command before and thus we have connected to a - * possibly new IP address. - * - */ -static void -ftp_pasv_verbose(struct connectdata *conn, - Curl_addrinfo *ai, - char *newhost, /* ascii version */ - int port) -{ - char buf[256]; - Curl_printable_address(ai, buf, sizeof(buf)); - infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port); -} - -/* - Check if this is a range download, and if so, set the internal variables - properly. - */ - -static CURLcode ftp_range(struct connectdata *conn) -{ - curl_off_t from, to; - curl_off_t totalsize=-1; - char *ptr; - char *ptr2; - struct SessionHandle *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(data->reqdata.use_range && data->reqdata.range) { - from=curlx_strtoofft(data->reqdata.range, &ptr, 0); - while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-'))) - ptr++; - to=curlx_strtoofft(ptr, &ptr2, 0); - if(ptr == ptr2) { - /* we didn't get any digit */ - to=-1; - } - if((-1 == to) && (from>=0)) { - /* X - */ - data->reqdata.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", - from)); - } - else if(from < 0) { - /* -Y */ - totalsize = -from; - data->reqdata.maxdownload = -from; - data->reqdata.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", - totalsize)); - } - else { - /* X-Y */ - totalsize = to-from; - data->reqdata.maxdownload = totalsize+1; /* include last byte */ - data->reqdata.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T - " getting %" FORMAT_OFF_T " bytes\n", - from, data->reqdata.maxdownload)); - } - DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T - " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n", - from, to, data->reqdata.maxdownload)); - ftpc->dont_check = TRUE; /* dont check for successful transfer */ - } - return CURLE_OK; -} - - -/* - * Curl_ftp_nextconnect() - * - * This function shall be called when the second FTP (data) connection is - * connected. - */ - -CURLcode Curl_ftp_nextconnect(struct connectdata *conn) -{ - struct SessionHandle *data=conn->data; - CURLcode result = CURLE_OK; - - /* the ftp struct is inited in Curl_ftp_connect() */ - struct FTP *ftp = data->reqdata.proto.ftp; - - DEBUGF(infof(data, "DO-MORE phase starts\n")); - - if(!ftp->no_transfer && !conn->bits.no_body) { - /* a transfer is about to take place */ - - if(data->set.upload) { - result = ftp_nb_type(conn, data->set.prefer_ascii, - FTP_STOR_TYPE); - if (result) - return result; - } - else { - /* download */ - ftp->downloadsize = -1; /* unknown as of yet */ - - result = ftp_range(conn); - if(result) - ; - else if((data->set.ftp_list_only) || !ftp->file) { - /* The specified path ends with a slash, and therefore we think this - is a directory that is requested, use LIST. But before that we - need to set ASCII transfer mode. */ - result = ftp_nb_type(conn, 1, FTP_LIST_TYPE); - if (result) - return result; - } - else { - result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE); - if (result) - return result; - } - } - result = ftp_easy_statemach(conn); - } - - if(ftp->no_transfer) - /* no data to transfer. FIX: it feels like a kludge to have this here - too! */ - result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - /* end of transfer */ - DEBUGF(infof(data, "DO-MORE phase ends with %d\n", result)); - - return result; -} - - - -/*********************************************************************** - * - * ftp_perform() - * - * This is the actual DO function for FTP. Get a file/directory according to - * the options previously setup. - */ - -static -CURLcode ftp_perform(struct connectdata *conn, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) -{ - /* this is FTP and no proxy */ - CURLcode result=CURLE_OK; - - DEBUGF(infof(conn->data, "DO phase starts\n")); - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - result = ftp_state_quote(conn, TRUE, FTP_QUOTE); - if(result) - return result; - - /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) - result = Curl_ftp_multi_statemach(conn, dophase_done); - else { - result = ftp_easy_statemach(conn); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; - - if(*dophase_done) { - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - - return result; -} - -/*********************************************************************** - * - * Curl_ftp() - * - * This function is registered as 'curl_do' function. It decodes the path - * parts etc as a wrapper to the actual DO function (ftp_perform). - * - * The input argument is already checked for validity. - */ -CURLcode Curl_ftp(struct connectdata *conn, bool *done) -{ - CURLcode retcode = CURLE_OK; - - *done = FALSE; /* default to false */ - - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct FTP' to play with. For new connections, - the struct FTP is allocated and setup in the Curl_ftp_connect() function. - */ - retcode = ftp_init(conn); - if(retcode) - return retcode; - - retcode = ftp_parse_url_path(conn); - if (retcode) - return retcode; - - retcode = ftp_regular_transfer(conn, done); - - return retcode; -} - -/*********************************************************************** - * - * Curl_(nb)ftpsendf() - * - * Sends the formated string as a ftp command to a ftp server - * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * - * The "nb" version is made to Never Block. - */ -CURLcode Curl_nbftpsendf(struct connectdata *conn, - const char *fmt, ...) -{ - ssize_t bytes_written; - char s[256]; - size_t write_len; - char *sptr=s; - CURLcode res = CURLE_OK; - struct SessionHandle *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - va_list ap; - va_start(ap, fmt); - vsnprintf(s, 250, fmt, ap); - va_end(ap); - - strcat(s, "\r\n"); /* append a trailing CRLF */ - - bytes_written=0; - write_len = strlen(s); - - ftp_respinit(conn); - -#ifdef CURL_DOES_CONVERSIONS - res = Curl_convert_to_network(data, s, write_len); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - return res; - } -#endif /* CURL_DOES_CONVERSIONS */ - - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); - - if(CURLE_OK != res) - return res; - - if(conn->data->set.verbose) - Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); - - if(bytes_written != (ssize_t)write_len) { - /* the whole chunk was not sent, store the rest of the data */ - write_len -= bytes_written; - sptr += bytes_written; - ftpc->sendthis = malloc(write_len); - if(ftpc->sendthis) { - memcpy(ftpc->sendthis, sptr, write_len); - ftpc->sendsize = ftpc->sendleft = write_len; - } - else { - failf(data, "out of memory"); - res = CURLE_OUT_OF_MEMORY; - } - } - else - ftpc->response = Curl_tvnow(); - - return res; -} - -CURLcode Curl_ftpsendf(struct connectdata *conn, - const char *fmt, ...) -{ - ssize_t bytes_written; - char s[256]; - size_t write_len; - char *sptr=s; - CURLcode res = CURLE_OK; - - va_list ap; - va_start(ap, fmt); - vsnprintf(s, 250, fmt, ap); - va_end(ap); - - strcat(s, "\r\n"); /* append a trailing CRLF */ - - bytes_written=0; - write_len = strlen(s); - -#ifdef CURL_DOES_CONVERSIONS - res = Curl_convert_to_network(conn->data, s, write_len); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - return(res); - } -#endif /* CURL_DOES_CONVERSIONS */ - - while(1) { - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); - - if(CURLE_OK != res) - break; - - if(conn->data->set.verbose) - Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); - - if(bytes_written != (ssize_t)write_len) { - write_len -= bytes_written; - sptr += bytes_written; - } - else - break; - } - - return res; -} - -/*********************************************************************** - * - * ftp_quit() - * - * This should be called before calling sclose() on an ftp control connection - * (not data connections). We should then wait for the response from the - * server before returning. The calling code should then try to close the - * connection. - * - */ -static CURLcode ftp_quit(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - if(conn->proto.ftpc.ctl_valid) { - NBFTPSENDF(conn, "QUIT", NULL); - state(conn, FTP_QUIT); - - result = ftp_easy_statemach(conn); - } - - return result; -} - -/*********************************************************************** - * - * Curl_ftp_disconnect() - * - * Disconnect from an FTP server. Cleanup protocol-specific per-connection - * resources. BLOCKING. - */ -CURLcode Curl_ftp_disconnect(struct connectdata *conn) -{ - struct ftp_conn *ftpc= &conn->proto.ftpc; - - /* We cannot send quit unconditionally. If this connection is stale or - 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's ok it - will try to send the QUIT command, otherwise it will just return. - */ - - /* The FTP session may or may not have been allocated/setup at this point! */ - if(conn->data->reqdata.proto.ftp) { - (void)ftp_quit(conn); /* ignore errors on the QUIT */ - - if(ftpc->entrypath) { - struct SessionHandle *data = conn->data; - data->state.most_recent_ftp_entrypath = NULL; - free(ftpc->entrypath); - ftpc->entrypath = NULL; - } - if(ftpc->cache) { - free(ftpc->cache); - ftpc->cache = NULL; - } - freedirs(conn); - if(ftpc->prevpath) { - free(ftpc->prevpath); - ftpc->prevpath = NULL; - } - } - return CURLE_OK; -} - -/*********************************************************************** - * - * ftp_parse_url_path() - * - * Parse the URL path into separate path components. - * - */ -static -CURLcode ftp_parse_url_path(struct connectdata *conn) -{ - CURLcode retcode = CURLE_OK; - struct SessionHandle *data = conn->data; - /* the ftp struct is already inited in ftp_connect() */ - struct FTP *ftp = data->reqdata.proto.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - size_t dlen; - char *slash_pos; /* position of the first '/' char in curpos */ - char *path_to_use = data->reqdata.path; - char *cur_pos; - - cur_pos = path_to_use; /* current position in path. point at the begin - of next path component */ - - ftpc->ctl_valid = FALSE; - ftpc->cwdfail = FALSE; - - switch(data->set.ftp_filemethod) { - case FTPFILE_NOCWD: - /* fastest, but less standard-compliant */ - ftp->file = data->reqdata.path; /* this is a full file path */ - break; - - case FTPFILE_SINGLECWD: - /* get the last slash */ - slash_pos=strrchr(cur_pos, '/'); - if(slash_pos || !cur_pos || !*cur_pos) { - ftpc->dirdepth = 1; /* we consider it to be a single dir */ - ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) - return CURLE_OUT_OF_MEMORY; - - ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", - slash_pos?(int)(slash_pos-cur_pos):1, - NULL); - if(!ftpc->dirs[0]) { - free(ftpc->dirs); - return CURLE_OUT_OF_MEMORY; - } - ftp->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ - } - else - ftp->file = cur_pos; /* this is a file name only */ - break; - - default: /* allow pretty much anything */ - case FTPFILE_MULTICWD: - ftpc->dirdepth = 0; - ftpc->diralloc = 5; /* default dir depth to allocate */ - ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) - return CURLE_OUT_OF_MEMORY; - - /* parse the URL path into separate path components */ - while ((slash_pos = strchr(cur_pos, '/')) != NULL) { - /* 1 or 0 to indicate absolute directory */ - bool absolute_dir = (bool)((cur_pos - data->reqdata.path > 0) && - (ftpc->dirdepth == 0)); - - /* seek out the next path component */ - if (slash_pos-cur_pos) { - /* we skip empty path components, like "x//y" since the FTP command - CWD requires a parameter and a non-existent parameter a) doesn't - work on many servers and b) has no effect on the others. */ - int len = (int)(slash_pos - cur_pos + absolute_dir); - ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data, - cur_pos - absolute_dir, - len, NULL); - if (!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ - failf(data, "no memory"); - freedirs(conn); - return CURLE_OUT_OF_MEMORY; - } - if (isBadFtpString(ftpc->dirs[ftpc->dirdepth])) { - freedirs(conn); - return CURLE_URL_MALFORMAT; - } - } - else { - cur_pos = slash_pos + 1; /* jump to the rest of the string */ - continue; - } - - if(!retcode) { - cur_pos = slash_pos + 1; /* jump to the rest of the string */ - if(++ftpc->dirdepth >= ftpc->diralloc) { - /* enlarge array */ - char *bigger; - ftpc->diralloc *= 2; /* double the size each time */ - bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0])); - if(!bigger) { - ftpc->dirdepth--; - freedirs(conn); - return CURLE_OUT_OF_MEMORY; - } - ftpc->dirs = (char **)bigger; - } - } - } - - ftp->file = cur_pos; /* the rest is the file name */ - } - - if(*ftp->file) { - ftp->file = curl_easy_unescape(conn->data, ftp->file, 0, NULL); - if(NULL == ftp->file) { - freedirs(conn); - failf(data, "no memory"); - return CURLE_OUT_OF_MEMORY; - } - if (isBadFtpString(ftp->file)) { - freedirs(conn); - return CURLE_URL_MALFORMAT; - } - } - else - ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL - pointer */ - - if(data->set.upload && !ftp->file && - (!ftp->no_transfer || conn->bits.no_body)) { - /* We need a file name when uploading. Return error! */ - failf(data, "Uploading to a URL without a file name!"); - return CURLE_URL_MALFORMAT; - } - - ftpc->cwddone = FALSE; /* default to not done */ - - if(ftpc->prevpath) { - /* prevpath is "raw" so we convert the input path before we compare the - strings */ - char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL); - if(!path) - return CURLE_OUT_OF_MEMORY; - - dlen = strlen(path) - (ftp->file?strlen(ftp->file):0); - if((dlen == strlen(ftpc->prevpath)) && - curl_strnequal(path, ftpc->prevpath, dlen)) { - infof(data, "Request has same path as previous transfer\n"); - ftpc->cwddone = TRUE; - } - free(path); - } - - return retcode; -} - -/* call this when the DO phase has completed */ -static CURLcode ftp_dophase_done(struct connectdata *conn, - bool connected) -{ - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->reqdata.proto.ftp; - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(connected) - result = Curl_ftp_nextconnect(conn); - - if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) { - /* Failure detected, close the second socket if it was created already */ - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - return result; - } - - if(ftp->no_transfer) - /* no data to transfer */ - result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - else if(!connected) - /* since we didn't connect now, we want do_more to get called */ - conn->bits.do_more = TRUE; - - ftpc->ctl_valid = TRUE; /* seems good */ - - return result; -} - -/* called from multi.c while DOing */ -CURLcode Curl_ftp_doing(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result; - result = Curl_ftp_multi_statemach(conn, dophase_done); - - if(*dophase_done) { - result = ftp_dophase_done(conn, FALSE /* not connected */); - - DEBUGF(infof(conn->data, "DO phase is complete\n")); - } - return result; -} - -/*********************************************************************** - * - * ftp_regular_transfer() - * - * The input argument is already checked for validity. - * - * Performs all commands done before a regular transfer between a local and a - * remote host. - * - * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the - * Curl_ftp_done() function without finding any major problem. - */ -static -CURLcode ftp_regular_transfer(struct connectdata *conn, - bool *dophase_done) -{ - CURLcode result=CURLE_OK; - bool connected=0; - struct SessionHandle *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - data->reqdata.size = -1; /* make sure this is unknown at this point */ - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); - - ftpc->ctl_valid = TRUE; /* starts good */ - - result = ftp_perform(conn, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ - - if(CURLE_OK == result) { - - if(!*dophase_done) - /* the DO phase has not completed yet */ - return CURLE_OK; - - result = ftp_dophase_done(conn, connected); - if(result) - return result; - } - else - freedirs(conn); - - return result; -} - -#endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/ftp.h b/Utilities/cmcurl/ftp.h deleted file mode 100644 index b64e705..0000000 --- a/Utilities/cmcurl/ftp.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __FTP_H -#define __FTP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifndef CURL_DISABLE_FTP -CURLcode Curl_ftp(struct connectdata *conn, bool *done); -CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature); -CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done); -CURLcode Curl_ftp_disconnect(struct connectdata *conn); -CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); -CURLcode Curl_nbftpsendf(struct connectdata *, const char *fmt, ...); -CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, - int *ftpcode); -CURLcode Curl_ftp_nextconnect(struct connectdata *conn); -CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done); -int Curl_ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -CURLcode Curl_ftp_doing(struct connectdata *conn, - bool *dophase_done); -#endif /* CURL_DISABLE_FTP */ -#endif /* __FTP_H */ diff --git a/Utilities/cmcurl/getenv.c b/Utilities/cmcurl/getenv.c deleted file mode 100644 index 4f955f8..0000000 --- a/Utilities/cmcurl/getenv.c +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include -#include - -#ifdef VMS -#include -#endif - -#include -#include "memory.h" - -#include "memdebug.h" - -static -char *GetEnv(const char *variable) -{ -#ifdef _WIN32_WCE - return NULL; -#else -#ifdef WIN32 - char env[MAX_PATH]; /* MAX_PATH is from windef.h */ - char *temp = getenv(variable); - env[0] = '\0'; - if (temp != NULL) - ExpandEnvironmentStrings(temp, env, sizeof(env)); -#else -#ifdef VMS - char *env = getenv(variable); - if (env && strcmp("HOME",variable) == 0) { - env = decc$translate_vms(env); - } -#else - /* no length control */ - char *env = getenv(variable); -#endif -#endif - return (env && env[0])?strdup(env):NULL; -#endif -} - -char *curl_getenv(const char *v) -{ - return GetEnv(v); -} diff --git a/Utilities/cmcurl/getinfo.c b/Utilities/cmcurl/getinfo.c deleted file mode 100644 index 5cf3bca..0000000 --- a/Utilities/cmcurl/getinfo.c +++ /dev/null @@ -1,234 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#include "urldata.h" -#include "getinfo.h" - -#include -#include -#include -#include -#include "memory.h" -#include "sslgen.h" - -/* Make this the last #include */ -#include "memdebug.h" - -/* - * This is supposed to be called in the beginning of a perform() session - * and should reset all session-info variables - */ -CURLcode Curl_initinfo(struct SessionHandle *data) -{ - struct Progress *pro = &data->progress; - struct PureInfo *info =&data->info; - - pro->t_nslookup = 0; - pro->t_connect = 0; - pro->t_pretransfer = 0; - pro->t_starttransfer = 0; - pro->timespent = 0; - pro->t_redirect = 0; - - info->httpcode = 0; - info->httpversion=0; - info->filetime=-1; /* -1 is an illegal time and thus means unknown */ - - if (info->contenttype) - free(info->contenttype); - info->contenttype = NULL; - - info->header_size = 0; - info->request_size = 0; - info->numconnects = 0; - return CURLE_OK; -} - -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) -{ - va_list arg; - long *param_longp=NULL; - double *param_doublep=NULL; - char **param_charp=NULL; - struct curl_slist **param_slistp=NULL; - char buf; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - va_start(arg, info); - - switch(info&CURLINFO_TYPEMASK) { - default: - return CURLE_BAD_FUNCTION_ARGUMENT; - case CURLINFO_STRING: - param_charp = va_arg(arg, char **); - if(NULL == param_charp) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - case CURLINFO_LONG: - param_longp = va_arg(arg, long *); - if(NULL == param_longp) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - case CURLINFO_DOUBLE: - param_doublep = va_arg(arg, double *); - if(NULL == param_doublep) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - case CURLINFO_SLIST: - param_slistp = va_arg(arg, struct curl_slist **); - if(NULL == param_slistp) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - } - - switch(info) { - case CURLINFO_EFFECTIVE_URL: - *param_charp = data->change.url?data->change.url:(char *)""; - break; - case CURLINFO_RESPONSE_CODE: - *param_longp = data->info.httpcode; - break; - case CURLINFO_HTTP_CONNECTCODE: - *param_longp = data->info.httpproxycode; - break; - case CURLINFO_FILETIME: - *param_longp = data->info.filetime; - break; - case CURLINFO_HEADER_SIZE: - *param_longp = data->info.header_size; - break; - case CURLINFO_REQUEST_SIZE: - *param_longp = data->info.request_size; - break; - case CURLINFO_TOTAL_TIME: - *param_doublep = data->progress.timespent; - break; - case CURLINFO_NAMELOOKUP_TIME: - *param_doublep = data->progress.t_nslookup; - break; - case CURLINFO_CONNECT_TIME: - *param_doublep = data->progress.t_connect; - break; - case CURLINFO_PRETRANSFER_TIME: - *param_doublep = data->progress.t_pretransfer; - break; - case CURLINFO_STARTTRANSFER_TIME: - *param_doublep = data->progress.t_starttransfer; - break; - case CURLINFO_SIZE_UPLOAD: - *param_doublep = (double)data->progress.uploaded; - break; - case CURLINFO_SIZE_DOWNLOAD: - *param_doublep = (double)data->progress.downloaded; - break; - case CURLINFO_SPEED_DOWNLOAD: - *param_doublep = (double)data->progress.dlspeed; - break; - case CURLINFO_SPEED_UPLOAD: - *param_doublep = (double)data->progress.ulspeed; - break; - case CURLINFO_SSL_VERIFYRESULT: - *param_longp = data->set.ssl.certverifyresult; - break; - case CURLINFO_CONTENT_LENGTH_DOWNLOAD: - *param_doublep = (double)data->progress.size_dl; - break; - case CURLINFO_CONTENT_LENGTH_UPLOAD: - *param_doublep = (double)data->progress.size_ul; - break; - case CURLINFO_REDIRECT_TIME: - *param_doublep = data->progress.t_redirect; - break; - case CURLINFO_REDIRECT_COUNT: - *param_longp = data->set.followlocation; - break; - case CURLINFO_CONTENT_TYPE: - *param_charp = data->info.contenttype; - break; - case CURLINFO_PRIVATE: - *param_charp = data->set.private_data; - break; - case CURLINFO_HTTPAUTH_AVAIL: - *param_longp = data->info.httpauthavail; - break; - case CURLINFO_PROXYAUTH_AVAIL: - *param_longp = data->info.proxyauthavail; - break; - case CURLINFO_OS_ERRNO: - *param_longp = data->state.os_errno; - break; - case CURLINFO_NUM_CONNECTS: - *param_longp = data->info.numconnects; - break; - case CURLINFO_SSL_ENGINES: - *param_slistp = Curl_ssl_engines_list(data); - break; - case CURLINFO_COOKIELIST: - *param_slistp = Curl_cookie_list(data); - break; - case CURLINFO_FTP_ENTRY_PATH: - /* Return the entrypath string from the most recent connection. - This pointer was copied from the connectdata structure by FTP. - The actual string may be free()ed by subsequent libcurl calls so - it must be copied to a safer area before the next libcurl call. - Callers must never free it themselves. */ - *param_charp = data->state.most_recent_ftp_entrypath; - break; - case CURLINFO_LASTSOCKET: - if((data->state.lastconnect != -1) && - (data->state.connc->connects[data->state.lastconnect] != NULL)) { - struct connectdata *c = data->state.connc->connects - [data->state.lastconnect]; - *param_longp = c->sock[FIRSTSOCKET]; - /* we have a socket connected, let's determine if the server shut down */ - /* determine if ssl */ - if(c->ssl[FIRSTSOCKET].use) { - /* use the SSL context */ - if (!Curl_ssl_check_cxn(c)) - *param_longp = -1; /* FIN received */ - } -/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ -#ifdef MSG_PEEK - else { - /* use the socket */ - if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { - *param_longp = -1; /* FIN received */ - } - } -#endif - } - else - *param_longp = -1; - break; - default: - return CURLE_BAD_FUNCTION_ARGUMENT; - } - return CURLE_OK; -} diff --git a/Utilities/cmcurl/getinfo.h b/Utilities/cmcurl/getinfo.h deleted file mode 100644 index 2fe1b5c..0000000 --- a/Utilities/cmcurl/getinfo.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __GETINFO_H -#define __GETINFO_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...); -CURLcode Curl_initinfo(struct SessionHandle *data); - -#endif diff --git a/Utilities/cmcurl/gtls.c b/Utilities/cmcurl/gtls.c deleted file mode 100644 index 250ecad..0000000 --- a/Utilities/cmcurl/gtls.c +++ /dev/null @@ -1,640 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code - * but sslgen.c should ever call or use these functions. - * - * Note: don't use the GnuTLS' *_t variable type names in this source code, - * since they were not present in 1.0.X. - */ - -#include "setup.h" -#ifdef USE_GNUTLS -#include -#include - -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "gtls.h" -#include "sslgen.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* Enable GnuTLS debugging by defining GTLSDEBUG */ -/*#define GTLSDEBUG */ - -#ifdef GTLSDEBUG -static void tls_log_func(int level, const char *str) -{ - fprintf(stderr, "|<%d>| %s", level, str); -} -#endif - -/* - * Custom push and pull callback functions used by GNU TLS to read and write - * to the socket. These functions are simple wrappers to send() and recv() - * (although here using the sread/swrite macros as defined by setup_once.h). - * We use custom functions rather than the GNU TLS defaults because it allows - * us to get specific about the fourth "flags" argument, and to use arbitrary - * private data with gnutls_transport_set_ptr if we wish. - */ -static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) -{ - return swrite(s, buf, len); -} - -static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) -{ - return sread(s, buf, len); -} - -/* Global GnuTLS init, called from Curl_ssl_init() */ -int Curl_gtls_init(void) -{ - gnutls_global_init(); -#ifdef GTLSDEBUG - gnutls_global_set_log_function(tls_log_func); - gnutls_global_set_log_level(2); -#endif - return 1; -} - -int Curl_gtls_cleanup(void) -{ - gnutls_global_deinit(); - return 1; -} - -static void showtime(struct SessionHandle *data, - const char *text, - time_t stamp) -{ - struct tm *tm; -#ifdef HAVE_GMTIME_R - struct tm buffer; - tm = (struct tm *)gmtime_r(&stamp, &buffer); -#else - tm = gmtime(&stamp); -#endif - snprintf(data->state.buffer, - BUFSIZE, - "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n", - text, - 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); - infof(data, "%s", data->state.buffer); -} - -/* this function does a BLOCKING SSL/TLS (re-)handshake */ -static CURLcode handshake(struct connectdata *conn, - gnutls_session session, - int sockindex, - bool duringconnect) -{ - struct SessionHandle *data = conn->data; - int rc; - - do { - rc = gnutls_handshake(session); - - if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - long timeout_ms = DEFAULT_CONNECT_TIMEOUT; - long has_passed; - - if(duringconnect && data->set.connecttimeout) - timeout_ms = data->set.connecttimeout*1000; - - if(data->set.timeout) { - /* get the strictest timeout of the ones converted to milliseconds */ - if((data->set.timeout*1000) < timeout_ms) - timeout_ms = data->set.timeout*1000; - } - - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - - /* subtract the passed time */ - timeout_ms -= has_passed; - - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEOUTED; - } - - rc = Curl_select(conn->sock[sockindex], - conn->sock[sockindex], (int)timeout_ms); - if(rc > 0) - /* reabable or writable, go loop*/ - continue; - else if(0 == rc) { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); - return CURLE_SSL_CONNECT_ERROR; - } - } - else - break; - } while(1); - - if (rc < 0) { - failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - - return CURLE_OK; -} - -static gnutls_x509_crt_fmt do_file_type(const char *type) -{ - if(!type || !type[0]) - return GNUTLS_X509_FMT_PEM; - if(curl_strequal(type, "PEM")) - return GNUTLS_X509_FMT_PEM; - if(curl_strequal(type, "DER")) - return GNUTLS_X509_FMT_DER; - return -1; -} - - -/* - * This function is called after the TCP connect has completed. Setup the TLS - * layer and do all necessary magic. - */ -CURLcode -Curl_gtls_connect(struct connectdata *conn, - int sockindex) - -{ - const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - struct SessionHandle *data = conn->data; - gnutls_session session; - int rc; - unsigned int cert_list_size; - const gnutls_datum *chainp; - unsigned int verify_status; - gnutls_x509_crt x509_cert; - char certbuf[256]; /* big enough? */ - size_t size; - unsigned int algo; - unsigned int bits; - time_t clock; - const char *ptr; - void *ssl_sessionid; - size_t ssl_idsize; - - /* GnuTLS only supports TLSv1 (and SSLv3?) */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* allocate a cred struct */ - rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); - if(rc < 0) { - failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - - if(data->set.ssl.CAfile) { - /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - - rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)\n", - data->set.ssl.CAfile, gnutls_strerror(rc)); - if (data->set.ssl.verifypeer) - return CURLE_SSL_CACERT_BADFILE; - } - else - infof(data, "found %d certificates in %s\n", - rc, data->set.ssl.CAfile); - } - - /* Initialize TLS session as a client */ - rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); - if(rc) { - failf(data, "gnutls_init() failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - - /* convenient assign */ - session = conn->ssl[sockindex].session; - - /* Use default priorities */ - rc = gnutls_set_default_priority(session); - if(rc < 0) - return CURLE_SSL_CONNECT_ERROR; - - /* Sets the priority on the certificate types supported by gnutls. Priority - is higher for types specified before others. After specifying the types - you want, you must append a 0. */ - rc = gnutls_certificate_type_set_priority(session, cert_type_priority); - if(rc < 0) - return CURLE_SSL_CONNECT_ERROR; - - if(data->set.cert) { - if( gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, data->set.cert, - data->set.key != 0 ? data->set.key : data->set.cert, - do_file_type(data->set.cert_type) ) ) { - failf(data, "error reading X.509 key or certificate file"); - return CURLE_SSL_CONNECT_ERROR; - } - } - - /* put the credentials to the current session */ - rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - conn->ssl[sockindex].cred); - - /* set the connection handle (file descriptor for the socket) */ - gnutls_transport_set_ptr(session, - (gnutls_transport_ptr)conn->sock[sockindex]); - - /* register callback functions to send and receive data. */ - gnutls_transport_set_push_function(session, Curl_gtls_push); - gnutls_transport_set_pull_function(session, Curl_gtls_pull); - - /* lowat must be set to zero when using custom push and pull functions. */ - gnutls_transport_set_lowat(session, 0); - - /* This might be a reconnect, so we check for a session ID in the cache - to speed up things */ - - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { - /* we got a session id, use it! */ - gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); - - /* Informational message */ - infof (data, "SSL re-using session ID\n"); - } - - rc = handshake(conn, session, sockindex, TRUE); - if(rc) - /* handshake() sets its own error message with failf() */ - return rc; - - /* This function will return the peer's raw certificate (chain) as sent by - the peer. These certificates are in raw format (DER encoded for - X.509). In case of a X.509 then a certificate list may be present. The - first certificate in the list is the peer's certificate, following the - issuer's certificate, then the issuer's issuer etc. */ - - chainp = gnutls_certificate_get_peers(session, &cert_list_size); - if(!chainp) { - if(data->set.ssl.verifyhost) { - failf(data, "failed to get server cert"); - return CURLE_SSL_PEER_CERTIFICATE; - } - infof(data, "\t common name: WARNING couldn't obtain\n"); - } - - /* This function will try to verify the peer's certificate and return its - status (trusted, invalid etc.). The value of status should be one or more - of the gnutls_certificate_status_t enumerated elements bitwise or'd. To - avoid denial of service attacks some default upper limits regarding the - certificate key size and chain size are set. To override them use - gnutls_certificate_set_verify_limits(). */ - - rc = gnutls_certificate_verify_peers2(session, &verify_status); - if (rc < 0) { - failf(data, "server cert verify failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - - /* verify_status is a bitmask of gnutls_certificate_status bits */ - if(verify_status & GNUTLS_CERT_INVALID) { - if (data->set.ssl.verifypeer) { - failf(data, "server certificate verification failed. CAfile: %s", - data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); - return CURLE_SSL_CACERT; - } - else - infof(data, "\t server certificate verification FAILED\n"); - } - else - infof(data, "\t server certificate verification OK\n"); - - /* initialize an X.509 certificate structure. */ - gnutls_x509_crt_init(&x509_cert); - - /* convert the given DER or PEM encoded Certificate to the native - gnutls_x509_crt_t format */ - gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - - size=sizeof(certbuf); - rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, - 0, /* the first and only one */ - FALSE, - certbuf, - &size); - if(rc) { - infof(data, "error fetching CN from cert:%s\n", - gnutls_strerror(rc)); - } - - /* This function will check if the given certificate's subject matches the - given hostname. This is a basic implementation of the matching described - in RFC2818 (HTTPS), which takes into account wildcards, and the subject - alternative name PKIX extension. Returns non zero on success, and zero on - failure. */ - rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); - - if(!rc) { - if (data->set.ssl.verifyhost > 1) { - failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, conn->host.dispname); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_PEER_CERTIFICATE; - } - else - infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, conn->host.dispname); - } - else - infof(data, "\t common name: %s (matched)\n", certbuf); - - /* Show: - - - ciphers used - - subject - - start date - - expire date - - common name - - issuer - - */ - - /* public key algorithm's parameters */ - algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); - infof(data, "\t certificate public key: %s\n", - gnutls_pk_algorithm_get_name(algo)); - - /* version of the X.509 certificate. */ - infof(data, "\t certificate version: #%d\n", - gnutls_x509_crt_get_version(x509_cert)); - - - size = sizeof(certbuf); - gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); - infof(data, "\t subject: %s\n", certbuf); - - clock = gnutls_x509_crt_get_activation_time(x509_cert); - showtime(data, "start date", clock); - - clock = gnutls_x509_crt_get_expiration_time(x509_cert); - showtime(data, "expire date", clock); - - size = sizeof(certbuf); - gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); - infof(data, "\t issuer: %s\n", certbuf); - - gnutls_x509_crt_deinit(x509_cert); - - /* compression algorithm (if any) */ - ptr = gnutls_compression_get_name(gnutls_compression_get(session)); - /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ - infof(data, "\t compression: %s\n", ptr); - - /* the name of the cipher used. ie 3DES. */ - ptr = gnutls_cipher_get_name(gnutls_cipher_get(session)); - infof(data, "\t cipher: %s\n", ptr); - - /* the MAC algorithms name. ie SHA1 */ - ptr = gnutls_mac_get_name(gnutls_mac_get(session)); - infof(data, "\t MAC: %s\n", ptr); - - if(!ssl_sessionid) { - /* this session was not previously in the cache, add it now */ - - /* get the session ID data size */ - gnutls_session_get_data(session, NULL, &ssl_idsize); - ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */ - - if(ssl_sessionid) { - /* extract session ID to the allocated buffer */ - gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize); - - /* store this session id */ - return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize); - } - } - - return CURLE_OK; -} - - -/* return number of sent (non-SSL) bytes */ -ssize_t Curl_gtls_send(struct connectdata *conn, - int sockindex, - void *mem, - size_t len) -{ - ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); - - if(rc < 0 ) { - if(rc == GNUTLS_E_AGAIN) - return 0; /* EWOULDBLOCK equivalent */ - rc = -1; /* generic error code for send failure */ - } - - return rc; -} - -void Curl_gtls_close_all(struct SessionHandle *data) -{ - /* FIX: make the OpenSSL code more generic and use parts of it here */ - (void)data; -} - -static void close_one(struct connectdata *conn, - int index) -{ - if(conn->ssl[index].session) { - gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); - gnutls_deinit(conn->ssl[index].session); - } - gnutls_certificate_free_credentials(conn->ssl[index].cred); -} - -void Curl_gtls_close(struct connectdata *conn) -{ - if(conn->ssl[0].use) - close_one(conn, 0); - if(conn->ssl[1].use) - close_one(conn, 1); -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) -{ - int result; - int retval = 0; - struct SessionHandle *data = conn->data; - int done = 0; - ssize_t nread; - char buf[120]; - - /* 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(conn->ssl[sockindex].session) { - while(!done) { - int what = Curl_select(conn->sock[sockindex], - CURL_SOCKET_BAD, 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(conn->ssl[sockindex].session, - buf, sizeof(buf)); - switch(result) { - case 0: - /* This is the expected response. There was no data but only - the close notify alert */ - done = 1; - break; - case GNUTLS_E_AGAIN: - case GNUTLS_E_INTERRUPTED: - infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); - break; - default: - retval = -1; - done = 1; - break; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - done = 1; - break; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); - retval = -1; - done = 1; - } - } - gnutls_deinit(conn->ssl[sockindex].session); - } - gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); - - conn->ssl[sockindex].session = NULL; - conn->ssl[sockindex].use = FALSE; - - return retval; -} - -/* - * If the read would block we return -1 and set 'wouldblock' to TRUE. - * Otherwise we return the amount of data read. Other errors should return -1 - * and set 'wouldblock' to FALSE. - */ -ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - bool *wouldblock) -{ - ssize_t ret; - - ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); - if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { - *wouldblock = TRUE; - return -1; - } - - if(ret == GNUTLS_E_REHANDSHAKE) { - /* BLOCKING call, this is bad but a work-around for now. Fixing this "the - proper way" takes a whole lot of work. */ - CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE); - if(rc) - /* handshake() writes error message on its own */ - return rc; - *wouldblock = TRUE; /* then return as if this was a wouldblock */ - return -1; - } - - *wouldblock = FALSE; - if (!ret) { - failf(conn->data, "Peer closed the TLS connection"); - return -1; - } - - if (ret < 0) { - failf(conn->data, "GnuTLS recv error (%d): %s", - (int)ret, gnutls_strerror(ret)); - return -1; - } - - return ret; -} - -void Curl_gtls_session_free(void *ptr) -{ - free(ptr); -} - -size_t Curl_gtls_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, " GnuTLS/%s", gnutls_check_version(NULL)); -} - -#endif /* USE_GNUTLS */ diff --git a/Utilities/cmcurl/gtls.h b/Utilities/cmcurl/gtls.h deleted file mode 100644 index bff3f86..0000000 --- a/Utilities/cmcurl/gtls.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __GTLS_H -#define __GTLS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -int Curl_gtls_init(void); -int Curl_gtls_cleanup(void); -CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); - -/* tell GnuTLS to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_gtls_close_all(struct SessionHandle *data); -void Curl_gtls_close(struct connectdata *conn); /* close a SSL connection */ - -/* return number of sent (non-SSL) bytes */ -ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex, - void *mem, size_t len); -ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - bool *wouldblock); -void Curl_gtls_session_free(void *ptr); -size_t Curl_gtls_version(char *buffer, size_t size); -int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); - -#endif diff --git a/Utilities/cmcurl/hash.c b/Utilities/cmcurl/hash.c deleted file mode 100644 index e004627..0000000 --- a/Utilities/cmcurl/hash.c +++ /dev/null @@ -1,315 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#include "hash.h" -#include "llist.h" -#include "memory.h" - -/* this must be the last include file */ -#include "memdebug.h" - -static unsigned long -hash_str(const char *key, size_t key_length) -{ - char *end = (char *) key + key_length; - unsigned long h = 5381; - - while (key < end) { - h += h << 5; - h ^= (unsigned long) *key++; - } - - return h; -} - -static void -hash_element_dtor(void *user, void *element) -{ - struct curl_hash *h = (struct curl_hash *) user; - struct curl_hash_element *e = (struct curl_hash_element *) element; - - if (e->key) - free(e->key); - - h->dtor(e->ptr); - - free(e); -} - -/* return 1 on error, 0 is fine */ -int -Curl_hash_init(struct curl_hash *h, int slots, curl_hash_dtor dtor) -{ - int i; - - h->dtor = dtor; - h->size = 0; - h->slots = slots; - - h->table = (struct curl_llist **) malloc(slots * sizeof(struct curl_llist *)); - if(h->table) { - for (i = 0; i < slots; ++i) { - h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); - if(!h->table[i]) { - while(i--) - Curl_llist_destroy(h->table[i], NULL); - free(h->table); - return 1; /* failure */ - } - } - return 0; /* fine */ - } - else - return 1; /* failure */ -} - -struct curl_hash * -Curl_hash_alloc(int slots, curl_hash_dtor dtor) -{ - struct curl_hash *h; - - h = (struct curl_hash *) malloc(sizeof(struct curl_hash)); - if (h) { - if(Curl_hash_init(h, slots, dtor)) { - /* failure */ - free(h); - h = NULL; - } - } - - return h; -} - -static int -hash_key_compare(char *key1, size_t key1_len, char *key2, size_t key2_len) -{ - if (key1_len == key2_len && - *key1 == *key2 && - memcmp(key1, key2, key1_len) == 0) { - return 1; - } - - return 0; -} - -static struct curl_hash_element * -mk_hash_element(char *key, size_t key_len, const void *p) -{ - struct curl_hash_element *he = - (struct curl_hash_element *) malloc(sizeof(struct curl_hash_element)); - - if(he) { - char *dup = malloc(key_len); - if(dup) { - /* copy the key */ - memcpy(dup, key, key_len); - - he->key = dup; - he->key_len = key_len; - he->ptr = (void *) p; - } - else { - /* failed to duplicate the key, free memory and fail */ - free(he); - he = NULL; - } - } - return he; -} - -#define find_slot(__h, __k, __k_len) (hash_str(__k, __k_len) % (__h)->slots) - -#define FETCH_LIST(x,y,z) x->table[find_slot(x, y, z)] - -/* Return the data in the hash. If there already was a match in the hash, - that data is returned. */ -void * -Curl_hash_add(struct curl_hash *h, char *key, size_t key_len, void *p) -{ - struct curl_hash_element *he; - struct curl_llist_element *le; - struct curl_llist *l = FETCH_LIST(h, key, key_len); - - for (le = l->head; le; le = le->next) { - he = (struct curl_hash_element *) le->ptr; - if (hash_key_compare(he->key, he->key_len, key, key_len)) { - h->dtor(p); /* remove the NEW entry */ - return he->ptr; /* return the EXISTING entry */ - } - } - - he = mk_hash_element(key, key_len, p); - if (he) { - if(Curl_llist_insert_next(l, l->tail, he)) { - ++h->size; - return p; /* return the new entry */ - } - /* - * Couldn't insert it, destroy the 'he' element and the key again. We - * don't call hash_element_dtor() since that would also call the - * "destructor" for the actual data 'p'. When we fail, we shall not touch - * that data. - */ - free(he->key); - free(he); - } - - return NULL; /* failure */ -} - -/* remove the identified hash entry, returns non-zero on failure */ -int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len) -{ - struct curl_llist_element *le; - struct curl_hash_element *he; - struct curl_llist *l = FETCH_LIST(h, key, key_len); - - for (le = l->head; le; le = le->next) { - he = le->ptr; - if (hash_key_compare(he->key, he->key_len, key, key_len)) { - Curl_llist_remove(l, le, (void *) h); - return 0; - } - } - return 1; -} - -void * -Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len) -{ - struct curl_llist_element *le; - struct curl_hash_element *he; - struct curl_llist *l = FETCH_LIST(h, key, key_len); - - for (le = l->head; le; le = le->next) { - he = le->ptr; - if (hash_key_compare(he->key, he->key_len, key, key_len)) { - return he->ptr; - } - } - - return NULL; -} - -#if defined(CURLDEBUG) && defined(AGGRESIVE_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 - -void -Curl_hash_clean(struct curl_hash *h) -{ - int i; - - for (i = 0; i < h->slots; ++i) { - Curl_llist_destroy(h->table[i], (void *) h); - } - - free(h->table); -} - -void -Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, - int (*comp)(void *, void *)) -{ - struct curl_llist_element *le; - struct curl_llist_element *lnext; - struct curl_llist *list; - int i; - - for (i = 0; i < h->slots; ++i) { - list = h->table[i]; - le = list->head; /* get first list entry */ - while(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(user, he->ptr)) { - Curl_llist_remove(list, le, (void *) h); - --h->size; /* one less entry in the hash now */ - } - le = lnext; - } - } -} - -void -Curl_hash_destroy(struct curl_hash *h) -{ - if (!h) - return; - - Curl_hash_clean(h); - free(h); -} - -#if 0 /* useful function for debugging hashes and their contents */ -void Curl_hash_print(struct curl_hash *h, - void (*func)(void *)) -{ - int i; - struct curl_llist_element *le; - struct curl_llist *list; - struct curl_hash_element *he; - if (!h) - return; - - fprintf(stderr, "=Hash dump=\n"); - - for (i = 0; i < h->slots; i++) { - list = h->table[i]; - le = list->head; /* get first list entry */ - if(le) { - fprintf(stderr, "index %d:", i); - while(le) { - he = le->ptr; - if(func) - func(he->ptr); - else - fprintf(stderr, " [%p]", he->ptr); - le = le->next; - } - fprintf(stderr, "\n"); - } - } -} -#endif diff --git a/Utilities/cmcurl/hash.h b/Utilities/cmcurl/hash.h deleted file mode 100644 index ceebb52..0000000 --- a/Utilities/cmcurl/hash.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __HASH_H -#define __HASH_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#include "llist.h" - -typedef void (*curl_hash_dtor)(void *); - -struct curl_hash { - struct curl_llist **table; - curl_hash_dtor dtor; - int slots; - size_t size; -}; - -struct curl_hash_element { - void *ptr; - char *key; - size_t key_len; -}; - - -int Curl_hash_init(struct curl_hash *, int, curl_hash_dtor); -struct curl_hash *Curl_hash_alloc(int, curl_hash_dtor); -void *Curl_hash_add(struct curl_hash *, char *, size_t, void *); -int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len); -void *Curl_hash_pick(struct curl_hash *, char *, size_t); -void Curl_hash_apply(struct curl_hash *h, void *user, - void (*cb)(void *user, void *ptr)); -int 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 *)); -void Curl_hash_destroy(struct curl_hash *h); - -#endif diff --git a/Utilities/cmcurl/hostares.c b/Utilities/cmcurl/hostares.c deleted file mode 100644 index 1db0f43..0000000 --- a/Utilities/cmcurl/hostares.c +++ /dev/null @@ -1,307 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "multiif.h" -#include "connect.h" /* for the Curl_sockerrno() proto */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#include "memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for ares-enabled builds - **********************************************************************/ - -#ifdef CURLRES_ARES - -/* - * Curl_resolv_fdset() is called when someone from the outside world (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. - * - * Returns: CURLE_OK always! - */ - -int Curl_resolv_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) - -{ - struct timeval maxtime; - struct timeval timeout; - int max = ares_getsock(conn->data->state.areschannel, - (int *)socks, numsocks); - - - maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; - maxtime.tv_usec = 0; - - ares_timeout(conn->data->state.areschannel, &maxtime, &timeout); - - Curl_expire(conn->data, - (timeout.tv_sec * 1000) + (timeout.tv_usec/1000) ); - - return max; -} - -/* - * Curl_is_resolved() is called repeatedly to check if a previous name resolve - * request has completed. It should also make sure to time-out if the - * operation seems to take too long. - * - * Returns normal CURLcode errors. - */ -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns) -{ - fd_set read_fds, write_fds; - struct timeval tv={0,0}; - struct SessionHandle *data = conn->data; - int nfds; - - FD_ZERO(&read_fds); - FD_ZERO(&write_fds); - - nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); - - (void)select(nfds, &read_fds, &write_fds, NULL, - (struct timeval *)&tv); - - /* Call ares_process() unconditonally here, even if we simply timed out - above, as otherwise the ares name resolve won't timeout! */ - ares_process(data->state.areschannel, &read_fds, &write_fds); - - *dns = NULL; - - if(conn->async.done) { - /* we're done, kill the ares handle */ - if(!conn->async.dns) { - failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, - ares_strerror(conn->async.status)); - return CURLE_COULDNT_RESOLVE_HOST; - } - *dns = conn->async.dns; - } - - return CURLE_OK; -} - -/* - * Curl_wait_for_resolv() waits for a resolve to finish. This function should - * be avoided since using this risk getting the multi interface to "hang". - * - * If 'entry' is non-NULL, make it point to the resolved dns entry - * - * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and - * CURLE_OPERATION_TIMEDOUT if a time-out occurred. - */ -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - CURLcode rc=CURLE_OK; - struct SessionHandle *data = conn->data; - long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */ - - /* now, see if there's a connect timeout or a regular timeout to - use instead of the default one */ - if(conn->data->set.connecttimeout) - timeout = conn->data->set.connecttimeout; - else if(conn->data->set.timeout) - timeout = conn->data->set.timeout; - - /* We convert the number of seconds into number of milliseconds here: */ - if(timeout < 2147483) - /* maximum amount of seconds that can be multiplied with 1000 and - still fit within 31 bits */ - timeout *= 1000; - else - timeout = 0x7fffffff; /* ridiculous amount of time anyway */ - - /* Wait for the name resolve query to complete. */ - while (1) { - int nfds=0; - fd_set read_fds, write_fds; - struct timeval *tvp, tv, store; - int count; - struct timeval now = Curl_tvnow(); - long timediff; - - store.tv_sec = (int)timeout/1000; - store.tv_usec = (timeout%1000)*1000; - - FD_ZERO(&read_fds); - FD_ZERO(&write_fds); - nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); - if (nfds == 0) - /* no file descriptors means we're done waiting */ - break; - tvp = ares_timeout(data->state.areschannel, &store, &tv); - count = select(nfds, &read_fds, &write_fds, NULL, tvp); - if (count < 0 && Curl_sockerrno() != EINVAL) - break; - - ares_process(data->state.areschannel, &read_fds, &write_fds); - - timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */ - timeout -= timediff?timediff:1; /* always deduct at least 1 */ - if (timeout < 0) { - /* our timeout, so we cancel the ares operation */ - ares_cancel(data->state.areschannel); - break; - } - } - - /* Operation complete, if the lookup was successful we now have the entry - in the cache. */ - - if(entry) - *entry = conn->async.dns; - - if(!conn->async.dns) { - /* a name was not resolved */ - if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { - failf(data, "Resolving host timed out: %s", conn->host.dispname); - rc = CURLE_OPERATION_TIMEDOUT; - } - else if(conn->async.done) { - failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, - ares_strerror(conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_HOST; - } - else - rc = CURLE_OPERATION_TIMEDOUT; - - /* close the connection, since we can't return failure here without - cleaning up this connection properly */ - conn->bits.close = TRUE; - } - - return rc; -} - -/* - * Curl_getaddrinfo() - when using ares - * - * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with - * Curl_freeaddrinfo(), nothing else. - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - char *bufp; - struct SessionHandle *data = conn->data; - in_addr_t in = inet_addr(hostname); - - *waitp = FALSE; - - if (in != CURL_INADDR_NONE) { - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(in, hostname, port); - } - - bufp = strdup(hostname); - - if(bufp) { - Curl_safefree(conn->async.hostname); - conn->async.hostname = bufp; - conn->async.port = port; - conn->async.done = FALSE; /* not done */ - conn->async.status = 0; /* clear */ - conn->async.dns = NULL; /* clear */ - - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname(data->state.areschannel, hostname, PF_INET, - (ares_host_callback)Curl_addrinfo4_callback, conn); - - *waitp = TRUE; /* please wait for the response */ - } - return NULL; /* no struct yet */ -} -#endif /* CURLRES_ARES */ diff --git a/Utilities/cmcurl/hostasyn.c b/Utilities/cmcurl/hostasyn.c deleted file mode 100644 index 3df1479..0000000 --- a/Utilities/cmcurl/hostasyn.c +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for builds using asynchronous name resolves - **********************************************************************/ -#ifdef CURLRES_ASYNCH -/* - * addrinfo_callback() gets called by ares, gethostbyname_thread() or - * getaddrinfo_thread() when we got the name resolved (or not!). - * - * If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the - * address field since it might be freed when this function returns. This - * operation stores the resolved data in the DNS cache. - * - * NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same - * pointer it is given as argument! - * - * The storage operation locks and unlocks the DNS cache. - */ -static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */ - int status, - void *addr) -{ - struct connectdata *conn = (struct connectdata *)arg; - struct Curl_dns_entry *dns = NULL; - CURLcode rc = CURLE_OK; - - conn->async.status = status; - - if(CURL_ASYNC_SUCCESS == status) { - - /* - * IPv4/ares: Curl_addrinfo_copy() copies the address and returns an - * allocated version. - * - * IPv6: Curl_addrinfo_copy() returns the input pointer! - */ - Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port); - if(ai) { - struct SessionHandle *data = conn->data; - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - dns = Curl_cache_addr(data, ai, - conn->async.hostname, - conn->async.port); - if(!dns) { - /* failed to store, cleanup and return error */ - Curl_freeaddrinfo(ai); - rc = CURLE_OUT_OF_MEMORY; - } - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - } - else - rc = CURLE_OUT_OF_MEMORY; - } - - conn->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 */ - conn->async.done = TRUE; - - /* ipv4: The input hostent struct will be freed by ares when we return from - this function */ - return rc; -} - -CURLcode Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */ - int status, - struct hostent *hostent) -{ - return addrinfo_callback(arg, status, hostent); -} - -#ifdef CURLRES_IPV6 -CURLcode Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */ - int status, - struct addrinfo *ai) -{ - /* NOTE: for CURLRES_ARES, the 'ai' argument is really a - * 'struct hostent' pointer. - */ - return addrinfo_callback(arg, status, ai); -} -#endif - -#endif /* CURLRES_ASYNC */ diff --git a/Utilities/cmcurl/hostip.c b/Utilities/cmcurl/hostip.c deleted file mode 100644 index 83f1564..0000000 --- a/Utilities/cmcurl/hostip.c +++ /dev/null @@ -1,636 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "inet_ntop.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * hostip.c explained - * ================== - * - * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c - * 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 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 - * asynchronous name resolves. This can be Windows or *nix. - * - * CURLRES_THREADED - is defined if libcurl is built to run under (native) - * Windows, and then the name resolve will be done in a new thread, and the - * supported API will be the same as for ares-builds. - * - * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If - * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is - * defined. - * - * The host*.c sources files are split up like this: - * - * hostip.c - method-independent resolver functions and utility functions - * hostasyn.c - functions for asynchronous name resolves - * hostsyn.c - functions for synchronous name resolves - * hostares.c - functions for ares-using name resolves - * hostthre.c - functions for threaded name resolves - * hostip4.c - ipv4-specific functions - * hostip6.c - ipv6-specific functions - * - * The hostip.h is the united header file for all this. It defines the - * CURLRES_* defines based on the config*.h and setup.h defines. - */ - -/* These two symbols are for the global DNS cache */ -static struct curl_hash hostname_cache; -static int host_cache_initialized; - -static void freednsentry(void *freethis); - -/* - * Curl_global_host_cache_init() initializes and sets up a global DNS cache. - * Global DNS cache is general badness. Do not use. This will be removed in - * a future version. Use the share interface instead! - */ -void Curl_global_host_cache_init(void) -{ - if (!host_cache_initialized) { - Curl_hash_init(&hostname_cache, 7, freednsentry); - host_cache_initialized = 1; - } -} - -/* - * Return a pointer to the global cache - */ -struct curl_hash *Curl_global_host_cache_get(void) -{ - return &hostname_cache; -} - -/* - * Destroy and cleanup the global DNS cache - */ -void Curl_global_host_cache_dtor(void) -{ - if (host_cache_initialized) { - Curl_hash_clean(&hostname_cache); - host_cache_initialized = 0; - } -} - -/* - * Return # of adresses in a Curl_addrinfo struct - */ -int Curl_num_addresses(const Curl_addrinfo *addr) -{ - int i; - for (i = 0; addr; addr = addr->ai_next, i++) - ; /* empty loop */ - return i; -} - -/* - * Curl_printable_address() returns a printable version of the 1st address - * given in the 'ip' argument. The result will be stored in the buf that is - * bufsize bytes big. - * - * If the conversion fails, it returns NULL. - */ -const char *Curl_printable_address(const Curl_addrinfo *ip, - char *buf, size_t bufsize) -{ - const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr; - int af = ip->ai_family; -#ifdef CURLRES_IPV6 - const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr; -#else - const void *ip6 = NULL; -#endif - - return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize); -} - -/* - * Return a hostcache id string for the providing host + port, to be used by - * the DNS caching. - */ -static char * -create_hostcache_id(const char *server, int port) -{ - /* create and return the new allocated entry */ - return aprintf("%s:%d", server, port); -} - -struct hostcache_prune_data { - int cache_timeout; - time_t now; -}; - -/* - * This function is set as a callback to be called for every entry in the DNS - * cache when we want to prune old unused entries. - * - * Returning non-zero means remove the entry, return 0 to keep it in the - * cache. - */ -static int -hostcache_timestamp_remove(void *datap, void *hc) -{ - struct hostcache_prune_data *data = - (struct hostcache_prune_data *) datap; - struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; - - if ((data->now - c->timestamp < data->cache_timeout) || - c->inuse) { - /* please don't remove */ - return 0; - } - - /* fine, remove */ - return 1; -} - -/* - * Prune the DNS cache. This assumes that a lock has already been taken. - */ -static void -hostcache_prune(struct curl_hash *hostcache, int cache_timeout, time_t now) -{ - struct hostcache_prune_data user; - - user.cache_timeout = cache_timeout; - user.now = now; - - Curl_hash_clean_with_criterium(hostcache, - (void *) &user, - hostcache_timestamp_remove); -} - -/* - * Library-wide function for pruning the DNS cache. This function takes and - * returns the appropriate locks. - */ -void Curl_hostcache_prune(struct SessionHandle *data) -{ - time_t now; - - if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache) - /* cache forever means never prune, and NULL hostcache means - we can't do it */ - return; - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - time(&now); - - /* Remove outdated and unused entries from the hostcache */ - hostcache_prune(data->dns.hostcache, - data->set.dns_cache_timeout, - now); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); -} - -static int -remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns) -{ - struct hostcache_prune_data user; - - if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache) - /* cache forever means never prune, and NULL hostcache means - we can't do it */ - return 0; - - time(&user.now); - user.cache_timeout = data->set.dns_cache_timeout; - - if ( !hostcache_timestamp_remove(&user,dns) ) - return 0; - - /* ok, we do need to clear the cache. although we need to remove just a - single entry we clean the entire hash, as no explicit delete function - is provided */ - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - Curl_hash_clean_with_criterium(data->dns.hostcache, - (void *) &user, - hostcache_timestamp_remove); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - return 1; -} - - -#ifdef HAVE_SIGSETJMP -/* Beware this is a global and unique instance. This is used to store the - return address that we can jump back to from inside a signal handler. This - is not thread-safe stuff. */ -sigjmp_buf curl_jmpenv; -#endif - - -/* - * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. - * - * When calling Curl_resolv() has resulted in a response with a returned - * address, we call this function to store the information in the dns - * cache etc - * - * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. - */ -struct Curl_dns_entry * -Curl_cache_addr(struct SessionHandle *data, - Curl_addrinfo *addr, - const char *hostname, - int port) -{ - char *entry_id; - size_t entry_len; - struct Curl_dns_entry *dns; - struct Curl_dns_entry *dns2; - time_t now; - - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if (!entry_id) - return NULL; - entry_len = strlen(entry_id); - - /* Create a new cache entry */ - dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1); - if (!dns) { - free(entry_id); - return NULL; - } - - dns->inuse = 0; /* init to not used */ - dns->addr = addr; /* this is the address(es) */ - - /* Store the resolved data in our DNS cache. This function may return a - pointer to an existing struct already present in the hash, and it may - return the same argument we pass in. Make no assumptions. */ - dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1, - (void *)dns); - if(!dns2) { - /* Major badness, run away. */ - free(dns); - free(entry_id); - return NULL; - } - time(&now); - dns = dns2; - - dns->timestamp = now; /* used now */ - dns->inuse++; /* mark entry as in-use */ - - /* free the allocated entry_id again */ - free(entry_id); - - return dns; -} - -/* - * 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'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_unlock() later (when you're - * done using this struct) to decrease the counter again. - * - * Return codes: - * - * CURLRESOLV_ERROR (-1) = error, no pointer - * CURLRESOLV_RESOLVED (0) = OK, pointer provided - * CURLRESOLV_PENDING (1) = waiting for response, no pointer - */ - -int Curl_resolv(struct connectdata *conn, - const char *hostname, - int port, - struct Curl_dns_entry **entry) -{ - char *entry_id = NULL; - struct Curl_dns_entry *dns = NULL; - size_t entry_len; - int wait; - struct SessionHandle *data = conn->data; - CURLcode result; - int rc; - *entry = NULL; - -#ifdef HAVE_SIGSETJMP - /* this allows us to time-out from the name resolver, as the timeout - will generate a signal and we will siglongjmp() from that here */ - if(!data->set.no_signal) { - if (sigsetjmp(curl_jmpenv, 1)) { - /* this is coming from a siglongjmp() */ - failf(data, "name lookup timed out"); - return CURLRESOLV_ERROR; - } - } -#endif - - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if (!entry_id) - return CURLRESOLV_ERROR; - - entry_len = strlen(entry_id); - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - /* See if its already in our dns cache */ - dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - /* free the allocated entry_id again */ - free(entry_id); - - /* See whether the returned entry is stale. Deliberately done after the - locked block */ - if ( remove_entry_if_stale(data,dns) ) - dns = NULL; /* the memory deallocation is being handled by the hash */ - - rc = CURLRESOLV_ERROR; /* default to failure */ - - if (!dns) { - /* The entry was not in the cache. Resolve it to IP address */ - - Curl_addrinfo *addr; - - /* Check what IP specifics the app has requested and if we can provide it. - * If not, bail out. */ - if(!Curl_ipvalid(data)) - return CURLRESOLV_ERROR; - - /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero - value indicating that we need to wait for the response to the resolve - call */ - addr = Curl_getaddrinfo(conn, hostname, port, &wait); - - if (!addr) { - if(wait) { - /* the response to our resolve call will come asynchronously at - a later time, good or bad */ - /* First, check that we haven't received the info by now */ - result = Curl_is_resolved(conn, &dns); - if(result) /* error detected */ - return CURLRESOLV_ERROR; - if(dns) - rc = CURLRESOLV_RESOLVED; /* pointer provided */ - else - rc = CURLRESOLV_PENDING; /* no info yet */ - } - } - else { - if(data->share) - 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, port); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - - if(!dns) - /* returned failure, bail out nicely */ - Curl_freeaddrinfo(addr); - else - rc = CURLRESOLV_RESOLVED; - } - } - else { - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - dns->inuse++; /* we use it! */ - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - rc = CURLRESOLV_RESOLVED; - } - - *entry = dns; - - return rc; -} - -/* - * 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. - */ -void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) -{ - curlassert(dns && (dns->inuse>0)); - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - dns->inuse--; - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); -} - -/* - * File-internal: free a cache dns entry. - */ -static void freednsentry(void *freethis) -{ - struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis; - - Curl_freeaddrinfo(p->addr); - - free(p); -} - -/* - * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it. - */ -struct curl_hash *Curl_mk_dnscache(void) -{ - return Curl_hash_alloc(7, freednsentry); -} - -#ifdef CURLRES_ADDRINFO_COPY - -/* align on even 64bit boundaries */ -#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7))) - -/* - * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and - * returns a pointer to the malloc()ed copy. You need to call free() on the - * returned buffer when you're done with it. - */ -Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port) -{ - const struct hostent *orig = org; - - return Curl_he2ai(orig, port); -} -#endif /* CURLRES_ADDRINFO_COPY */ - -/*********************************************************************** - * Only for plain-ipv4 and c-ares builds - **********************************************************************/ - -#if defined(CURLRES_IPV4) || defined(CURLRES_ARES) -/* - * This is a function for freeing name information in a protocol independent - * way. - */ -void Curl_freeaddrinfo(Curl_addrinfo *ai) -{ - Curl_addrinfo *next; - - /* walk over the list and free all entries */ - while(ai) { - next = ai->ai_next; - free(ai); - ai = next; - } -} - -struct namebuf { - struct hostent hostentry; - char *h_addr_list[2]; - struct in_addr addrentry; - char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */ -}; - -/* - * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter - * together with a pointer to the string version of the address, and it - * returns a Curl_addrinfo chain filled in correctly with information for this - * address/host. - * - * The input parameters ARE NOT checked for validity but they are expected - * to have been checked already when this is called. - */ -Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port) -{ - Curl_addrinfo *ai; - struct hostent *h; - struct in_addr *addrentry; - struct namebuf buffer; - struct namebuf *buf = &buffer; - - h = &buf->hostentry; - h->h_addr_list = &buf->h_addr_list[0]; - addrentry = &buf->addrentry; -#ifdef _CRAY - /* On UNICOS, s_addr is a bit field and for some reason assigning to it - * doesn't work. There must be a better fix than this ugly hack. - */ - memcpy(addrentry, &num, SIZEOF_in_addr); -#else - addrentry->s_addr = num; -#endif - h->h_addr_list[0] = (char*)addrentry; - h->h_addr_list[1] = NULL; - h->h_addrtype = AF_INET; - h->h_length = sizeof(*addrentry); - h->h_name = &buf->h_name[0]; - h->h_aliases = NULL; - - /* Now store the dotted version of the address */ - snprintf((char *)h->h_name, 16, "%s", hostname); - - ai = Curl_he2ai(h, port); - - return ai; -} -#endif - - diff --git a/Utilities/cmcurl/hostip.h b/Utilities/cmcurl/hostip.h deleted file mode 100644 index e6d63ca..0000000 --- a/Utilities/cmcurl/hostip.h +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef __HOSTIP_H -#define __HOSTIP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include "hash.h" - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t uint32_t -#endif - -/* - * Setup comfortable CURLRES_* defines to use in the host*.c sources. - */ - -#ifdef USE_ARES -#define CURLRES_ASYNCH -#define CURLRES_ARES -#endif - -#ifdef USE_THREADING_GETHOSTBYNAME -#define CURLRES_ASYNCH -#define CURLRES_THREADED -#endif - -#ifdef USE_THREADING_GETADDRINFO -#define CURLRES_ASYNCH -#define CURLRES_THREADED -#endif - -#ifdef ENABLE_IPV6 -#define CURLRES_IPV6 -#else -#define CURLRES_IPV4 -#endif - -#if defined(CURLRES_IPV4) || defined(CURLRES_ARES) -#if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH) -/* If built for ipv4 and missing gethostbyname_r(), or if using async name - resolve, we need the Curl_addrinfo_copy() function (which itself needs the - Curl_he2ai() function)) */ -#define CURLRES_ADDRINFO_COPY -#endif -#endif /* IPv4/ares-only */ - -#ifndef CURLRES_ASYNCH -#define CURLRES_SYNCH -#endif - -#ifndef USE_LIBIDN -#define CURLRES_IDN -#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 - * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes! - */ -#define CURL_HOSTENT_SIZE 9000 - -#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this - many seconds for a name resolve */ - -#ifdef CURLRES_ARES -#define CURL_ASYNC_SUCCESS ARES_SUCCESS -#else -#define CURL_ASYNC_SUCCESS CURLE_OK -#define ares_cancel(x) do {} while(0) -#define ares_destroy(x) do {} while(0) -#endif - -/* - * Curl_addrinfo MUST be used for all name resolved info. - */ -#ifdef CURLRES_IPV6 -typedef struct addrinfo Curl_addrinfo; -#else -/* OK, so some ipv4-only include tree probably have the addrinfo struct, but - to work even on those that don't, we provide our own look-alike! */ -struct Curl_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */ - char *ai_canonname; - struct sockaddr *ai_addr; - struct Curl_addrinfo *ai_next; -}; -typedef struct Curl_addrinfo Curl_addrinfo; -#endif - -struct addrinfo; -struct hostent; -struct SessionHandle; -struct connectdata; - -void Curl_global_host_cache_init(void); -void Curl_global_host_cache_dtor(void); -struct curl_hash *Curl_global_host_cache_get(void); - -#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache) - -struct Curl_dns_entry { - Curl_addrinfo *addr; - time_t timestamp; - long inuse; /* use-counter, make very sure you decrease this - when you're done using the address you received */ -}; - -/* - * Curl_resolv() returns an entry with the info for the specified host - * and port. - * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after - * use, or we'll leak memory! - */ -/* return codes */ -#define CURLRESOLV_ERROR -1 -#define CURLRESOLV_RESOLVED 0 -#define CURLRESOLV_PENDING 1 -int Curl_resolv(struct connectdata *conn, const char *hostname, - int port, struct Curl_dns_entry **dnsentry); - -/* - * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've - * been set and returns TRUE if they are OK. - */ -bool Curl_ipvalid(struct SessionHandle *data); - -/* - * Curl_getaddrinfo() is the generic low-level name resolve API within this - * source file. There are several versions of this function - for different - * name resolve layers (selected at build-time). They all take this same set - * of arguments - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp); - -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns); -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **dnsentry); - -/* Curl_resolv_getsock() is a generic function that exists in multiple - versions depending on what name resolve technology we've built to use. The - function is called from the multi_getsock() function. 'sock' is a pointer - to an array to hold the file descriptors, with 'numsock' being the size of - that array (in number of entries). This function is supposed to return - bitmask indicating what file descriptors (referring to array indexes in the - 'sock' array) to wait for, read/write. */ -int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *sock, - int numsocks); - -/* unlock a previously resolved dns entry */ -void Curl_resolv_unlock(struct SessionHandle *data, - struct Curl_dns_entry *dns); - -/* for debugging purposes only: */ -void Curl_scan_cache_used(void *user, void *ptr); - -/* free name info */ -void Curl_freeaddrinfo(Curl_addrinfo *freeaddr); - -/* make a new dns cache and return the handle */ -struct curl_hash *Curl_mk_dnscache(void); - -/* prune old entries from the DNS cache */ -void Curl_hostcache_prune(struct SessionHandle *data); - -/* Return # of adresses in a Curl_addrinfo struct */ -int Curl_num_addresses (const Curl_addrinfo *addr); - -#ifdef CURLDEBUG -void curl_dofreeaddrinfo(struct addrinfo *freethis, - int line, const char *source); -int curl_dogetaddrinfo(const char *hostname, const char *service, - struct addrinfo *hints, - struct addrinfo **result, - int line, const char *source); -#ifdef HAVE_GETNAMEINFO -int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, - GETNAMEINFO_TYPE_ARG2 salen, - char *host, GETNAMEINFO_TYPE_ARG46 hostlen, - char *serv, GETNAMEINFO_TYPE_ARG46 servlen, - GETNAMEINFO_TYPE_ARG7 flags, - int line, const char *source); -#endif -#endif - -/* This is the callback function that is used when we build with asynch - resolve, ipv4 */ -CURLcode Curl_addrinfo4_callback(void *arg, - int status, - struct hostent *hostent); -/* This is the callback function that is used when we build with asynch - resolve, ipv6 */ -CURLcode Curl_addrinfo6_callback(void *arg, - int status, - struct addrinfo *ai); - - -/* [ipv4/ares only] Creates a Curl_addrinfo struct from a numerical-only IP - address */ -Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port); - -/* [ipv4/ares only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain - and returns it */ -Curl_addrinfo *Curl_he2ai(const struct hostent *, int port); - -/* Clone a Curl_addrinfo struct, works protocol independently */ -Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port); - -/* - * Curl_printable_address() returns a printable version of the 1st address - * given in the 'ip' argument. The result will be stored in the buf that is - * bufsize bytes big. - */ -const char *Curl_printable_address(const Curl_addrinfo *ip, - char *buf, size_t bufsize); - -/* - * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. - * - * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. - */ -struct Curl_dns_entry * -Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, - const char *hostname, int port); - -/* - * Curl_destroy_thread_data() cleans up async resolver data. - * Complementary of ares_destroy. - */ -struct Curl_async; /* forward-declaration */ -void Curl_destroy_thread_data(struct Curl_async *async); - -#ifndef INADDR_NONE -#define CURL_INADDR_NONE (in_addr_t) ~0 -#else -#define CURL_INADDR_NONE INADDR_NONE -#endif - - - - -#endif diff --git a/Utilities/cmcurl/hostip4.c b/Utilities/cmcurl/hostip4.c deleted file mode 100644 index 877baa2..0000000 --- a/Utilities/cmcurl/hostip4.c +++ /dev/null @@ -1,389 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "inet_pton.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for plain-ipv4 builds - **********************************************************************/ -#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */ -/* - * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've - * been set and returns TRUE if they are OK. - */ -bool Curl_ipvalid(struct SessionHandle *data) -{ - if(data->set.ip_version == CURL_IPRESOLVE_V6) - /* an ipv6 address was requested and we can't get/use one */ - return FALSE; - - return TRUE; /* OK, proceed */ -} - -#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */ - -/* - * Curl_getaddrinfo() - the ipv4 synchronous version. - * - * The original code to this function was from the Dancer source code, written - * by Bjorn Reese, it has since been patched and modified considerably. - * - * gethostbyname_r() is the thread-safe version of the gethostbyname() - * function. When we build for plain IPv4, we attempt to use this - * function. There are _three_ different gethostbyname_r() versions, and we - * 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 - * flavours have thread-safe versions of the plain gethostbyname() etc. - * - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - Curl_addrinfo *ai = NULL; - struct hostent *h = NULL; - in_addr_t in; - struct SessionHandle *data = conn->data; - struct hostent *buf = NULL; - - (void)port; /* unused in IPv4 code */ - - *waitp = 0; /* don't wait, we act synchronously */ - - if(1 == Curl_inet_pton(AF_INET, hostname, &in)) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(in, hostname, port); - -#if defined(HAVE_GETHOSTBYNAME_R) - /* - * gethostbyname_r() is the preferred resolve function for many platforms. - * Since there are three different versions of it, the following code is - * somewhat #ifdef-ridden. - */ - else { - int h_errnop; - int res=ERANGE; - - buf = (struct hostent *)calloc(CURL_HOSTENT_SIZE, 1); - if(!buf) - return NULL; /* major failure */ - /* - * The clearing of the buffer is a workaround for a gethostbyname_r bug in - * qnx nto and it is also _required_ for some of these functions on some - * platforms. - */ - -#ifdef HAVE_GETHOSTBYNAME_R_5 - /* Solaris, IRIX and more */ - (void)res; /* prevent compiler warning */ - h = gethostbyname_r(hostname, - (struct hostent *)buf, - (char *)buf + sizeof(struct hostent), - CURL_HOSTENT_SIZE - sizeof(struct hostent), - &h_errnop); - - /* If the buffer is too small, it returns NULL and sets errno to - * ERANGE. The errno is thread safe if this is compiled with - * -D_REENTRANT as then the 'errno' variable is a macro defined to get - * used properly for threads. - */ - - if(h) { - ; - } - else -#endif /* HAVE_GETHOSTBYNAME_R_5 */ -#ifdef HAVE_GETHOSTBYNAME_R_6 - /* Linux */ - - res=gethostbyname_r(hostname, - (struct hostent *)buf, - (char *)buf + sizeof(struct hostent), - CURL_HOSTENT_SIZE - sizeof(struct hostent), - &h, /* DIFFERENCE */ - &h_errnop); - /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a - * sudden this function returns EAGAIN if the given buffer size is too - * small. Previous versions are known to return ERANGE for the same - * problem. - * - * 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. - * - * For now, we do that and thus we may call the function repeatedly and - * fail for older glibc versions that return EAGAIN, until we run out of - * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). - * - * If anyone has a better fix, please tell us! - * - * ------------------------------------------------------------------- - * - * On October 23rd 2003, Dan C dug up more details on the mysteries of - * 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 can't - * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 - * (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 - * thread-safe variable. - */ - - if(!h) /* failure */ -#endif/* HAVE_GETHOSTBYNAME_R_6 */ -#ifdef HAVE_GETHOSTBYNAME_R_3 - /* AIX, Digital Unix/Tru64, HPUX 10, more? */ - - /* 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 - * our caching system breaks down horribly. Luckily for us though, AIX 4.3 - * and more recent versions have a "completely thread-safe"[*] libc where - * all the data is stored in thread-specific memory areas making calls to - * the plain old gethostbyname() work fine even for multi-threaded - * programs. - * - * This AIX 4.3 or later detection is all made in the configure script. - * - * Troels Walsted Hansen helped us work this out on March 3rd, 2003. - * - * [*] = much later we've found out that it isn't at all "completely - * thread-safe", but at least the gethostbyname() function is. - */ - - if(CURL_HOSTENT_SIZE >= - (sizeof(struct hostent)+sizeof(struct hostent_data))) { - - /* August 22nd, 2000: Albert Chin-A-Young brought an updated version - * that should work! September 20: Richard Prescott worked on the buffer - * size dilemma. - */ - - res = gethostbyname_r(hostname, - (struct hostent *)buf, - (struct hostent_data *)((char *)buf + - sizeof(struct hostent))); - h_errnop= errno; /* we don't deal with this, but set it anyway */ - } - else - res = -1; /* failure, too smallish buffer size */ - - if(!res) { /* success */ - - h = buf; /* result expected in h */ - - /* This is the worst kind of the different gethostbyname_r() interfaces. - * 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 - * memory area to the actually used amount. - */ - } - else -#endif /* HAVE_GETHOSTBYNAME_R_3 */ - { - infof(data, "gethostbyname_r(2) failed for %s\n", hostname); - h = NULL; /* set return code to NULL */ - free(buf); - } -#else /* HAVE_GETHOSTBYNAME_R */ - /* - * Here is code for platforms that don't have gethostbyname_r() or for - * which the gethostbyname() is the preferred() function. - */ - else { - h = gethostbyname(hostname); - if (!h) - infof(data, "gethostbyname(2) failed for %s\n", hostname); -#endif /*HAVE_GETHOSTBYNAME_R */ - } - - if(h) { - ai = Curl_he2ai(h, port); - - if (buf) /* used a *_r() function */ - free(buf); - } - - return ai; -} - -#endif /* CURLRES_SYNCH */ -#endif /* CURLRES_IPV4 */ - -/* - * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct. - * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6 - * stacks, but for all hosts and environments. - * - * Curl_addrinfo defined in "lib/hostip.h" - * - * struct Curl_addrinfo { - * int ai_flags; - * int ai_family; - * int ai_socktype; - * int ai_protocol; - * socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * - * char *ai_canonname; - * struct sockaddr *ai_addr; - * struct Curl_addrinfo *ai_next; - * }; - * - * hostent defined in - * - * struct hostent { - * char *h_name; - * char **h_aliases; - * int h_addrtype; - * int h_length; - * char **h_addr_list; - * }; - * - * for backward compatibility: - * - * #define h_addr h_addr_list[0] - */ - -Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port) -{ - Curl_addrinfo *ai; - Curl_addrinfo *prevai = NULL; - Curl_addrinfo *firstai = NULL; - struct sockaddr_in *addr; - int i; - struct in_addr *curr; - - if(!he) - /* no input == no output! */ - return NULL; - - for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]) != NULL; i++) { - - ai = calloc(1, sizeof(Curl_addrinfo) + sizeof(struct sockaddr_in)); - - if(!ai) - break; - - if(!firstai) - /* store the pointer we want to return from this function */ - firstai = ai; - - if(prevai) - /* make the previous entry point to this */ - prevai->ai_next = ai; - - ai->ai_family = AF_INET; /* we only support this */ - - /* we return all names as STREAM, so when using this address for TFTP - the type must be ignored and conn->socktype be used instead! */ - ai->ai_socktype = SOCK_STREAM; - - ai->ai_addrlen = sizeof(struct sockaddr_in); - /* make the ai_addr point to the address immediately following this struct - and use that area to store the address */ - ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo)); - - /* leave the rest of the struct filled with zero */ - - addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */ - - memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr)); - addr->sin_family = he->h_addrtype; - addr->sin_port = htons((unsigned short)port); - - prevai = ai; - } - return firstai; -} - diff --git a/Utilities/cmcurl/hostip6.c b/Utilities/cmcurl/hostip6.c deleted file mode 100644 index c8bbdb5..0000000 --- a/Utilities/cmcurl/hostip6.c +++ /dev/null @@ -1,306 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "inet_pton.h" -#include "connect.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for ipv6-enabled builds - **********************************************************************/ -#ifdef CURLRES_IPV6 -#ifndef CURLRES_ARES -/* - * This is a wrapper function for freeing name information in a protocol - * independent way. This takes care of using the appropriate underlaying - * function. - */ -void Curl_freeaddrinfo(Curl_addrinfo *p) -{ - freeaddrinfo(p); -} - -#ifdef CURLRES_ASYNCH -/* - * Curl_addrinfo_copy() is used by the asynch callback to copy a given - * address. But this is an ipv6 build and then we don't copy the address, we - * just return the same pointer! - */ -Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port) -{ - (void) port; - return (Curl_addrinfo*)orig; -} -#endif /* CURLRES_ASYNCH */ -#endif /* CURLRES_ARES */ - -#ifdef CURLDEBUG -/* These are 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 didn't wanna include in memdebug.c - */ -int curl_dogetaddrinfo(const char *hostname, const char *service, - struct addrinfo *hints, - struct addrinfo **result, - int line, const char *source) -{ - int res=(getaddrinfo)(hostname, service, hints, result); - if(0 == res) { - /* success */ - if(logfile) - fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n", - source, line, (void *)*result); - } - else { - if(logfile) - fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n", - source, line); - } - return res; -} - -/* - * For CURLRES_ARS, this should be written using ares_gethostbyaddr() - * (ignoring the fact c-ares doesn't return 'serv'). - */ -#ifdef HAVE_GETNAMEINFO -int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, - GETNAMEINFO_TYPE_ARG2 salen, - char *host, GETNAMEINFO_TYPE_ARG46 hostlen, - char *serv, GETNAMEINFO_TYPE_ARG46 servlen, - GETNAMEINFO_TYPE_ARG7 flags, - int line, const char *source) -{ - int res = (getnameinfo)(sa, salen, - host, hostlen, - serv, servlen, - flags); - if(0 == res) { - /* success */ - if(logfile) - fprintf(logfile, "GETNAME %s:%d getnameinfo()\n", - source, line); - } - else { - if(logfile) - fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n", - source, line, res); - } - return res; -} -#endif - -void curl_dofreeaddrinfo(struct addrinfo *freethis, - int line, const char *source) -{ - (freeaddrinfo)(freethis); - if(logfile) - fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n", - source, line, (void *)freethis); -} -#endif /* CURLDEBUG */ - -/* - * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've - * been set and returns TRUE if they are OK. - */ -bool Curl_ipvalid(struct SessionHandle *data) -{ - if(data->set.ip_version == CURL_IPRESOLVE_V6) { - /* see if we have an IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); - if (s == CURL_SOCKET_BAD) - /* an ipv6 address was requested and we can't get/use one */ - return FALSE; - sclose(s); - } - return TRUE; -} - -#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES) - -#ifdef DEBUG_ADDRINFO -static void dump_addrinfo(struct connectdata *conn, const struct addrinfo *ai) -{ - printf("dump_addrinfo:\n"); - for ( ; ai; ai = ai->ai_next) { - char buf[INET6_ADDRSTRLEN]; - - printf(" fam %2d, CNAME %s, ", - ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); - if (Curl_printable_address(ai, buf, sizeof(buf))) - printf("%s\n", buf); - else - printf("failed; %s\n", Curl_strerror(conn, Curl_sockerrno())); - } -} -#else -#define dump_addrinfo(x,y) -#endif - -/* - * Curl_getaddrinfo() when built ipv6-enabled (non-threading and - * non-ares version). - * - * Returns name information about the given hostname and port number. If - * successful, the 'addrinfo' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with - * Curl_freeaddrinfo(), nothing else. - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - struct addrinfo hints, *res; - int error; - char sbuf[NI_MAXSERV]; - char *sbufptr = NULL; - char addrbuf[128]; - curl_socket_t s; - int pf; - struct SessionHandle *data = conn->data; - - *waitp=0; /* don't wait, we have the response now */ - - /* see if we have an IPv6 stack */ - s = socket(PF_INET6, SOCK_DGRAM, 0); - if (s == CURL_SOCKET_BAD) { - /* Some non-IPv6 stacks have been found to make very slow name resolves - * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if - * the stack seems to be a non-ipv6 one. */ - - pf = PF_INET; - } - else { - /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest - * possible checks. And close the socket again. - */ - sclose(s); - - /* - * Check if a more limited name resolve has been requested. - */ - switch(data->set.ip_version) { - case CURL_IPRESOLVE_V4: - pf = PF_INET; - break; - case CURL_IPRESOLVE_V6: - pf = PF_INET6; - break; - default: - pf = PF_UNSPEC; - break; - } - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = pf; - hints.ai_socktype = conn->socktype; - - if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || - (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { - /* the given address is numerical only, prevent a reverse lookup */ - hints.ai_flags = AI_NUMERICHOST; - } -#if 0 /* removed nov 8 2005 before 7.15.1 */ - else - hints.ai_flags = AI_CANONNAME; -#endif - - if(port) { - snprintf(sbuf, sizeof(sbuf), "%d", port); - sbufptr=sbuf; - } - error = getaddrinfo(hostname, sbufptr, &hints, &res); - if (error) { - infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port); - return NULL; - } - - dump_addrinfo(conn, res); - - return res; -} -#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */ -#endif /* ipv6 */ - diff --git a/Utilities/cmcurl/hostsyn.c b/Utilities/cmcurl/hostsyn.c deleted file mode 100644 index 2f816b8..0000000 --- a/Utilities/cmcurl/hostsyn.c +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for builds using synchronous name resolves - **********************************************************************/ -#ifdef CURLRES_SYNCH - -/* - * Curl_wait_for_resolv() for synch-builds. Curl_resolv() can never return - * wait==TRUE, so this function will never be called. If it still gets called, - * we return failure at once. - * - * We provide this function only to allow multi.c to remain unaware if we are - * doing asynch resolves or not. - */ -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - (void)conn; - *entry=NULL; - return CURLE_COULDNT_RESOLVE_HOST; -} - -/* - * This function will never be called when synch-built. If it still gets - * called, we return failure at once. - * - * We provide this function only to allow multi.c to remain unaware if we are - * doing asynch resolves or not. - */ -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns) -{ - (void)conn; - *dns = NULL; - - return CURLE_COULDNT_RESOLVE_HOST; -} - -/* - * We just return OK, this function is never actually used for synch builds. - * It is present here to keep #ifdefs out from multi.c - */ - -int Curl_resolv_getsock(struct connectdata *conn, - curl_socket_t *sock, - int numsocks) -{ - (void)conn; - (void)sock; - (void)numsocks; - - return 0; /* no bits since we don't use any socks */ -} - -#endif /* truly sync */ diff --git a/Utilities/cmcurl/hostthre.c b/Utilities/cmcurl/hostthre.c deleted file mode 100644 index 12e31ea..0000000 --- a/Utilities/cmcurl/hostthre.c +++ /dev/null @@ -1,840 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef VMS -#include -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "multiif.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "inet_ntop.h" - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX) -#pragma message ("No _beginthreadex() available in this RTL") -#endif - -/*********************************************************************** - * Only for Windows threaded name resolves builds - **********************************************************************/ -#ifdef CURLRES_THREADED - -/* This function is used to init a threaded resolve */ -static bool init_resolve_thread(struct connectdata *conn, - const char *hostname, int port, - const Curl_addrinfo *hints); - -#ifdef CURLRES_IPV4 - #define THREAD_FUNC gethostbyname_thread - #define THREAD_NAME "gethostbyname_thread" -#else - #define THREAD_FUNC getaddrinfo_thread - #define THREAD_NAME "getaddrinfo_thread" -#endif - -#if defined(DEBUG_THREADING_GETHOSTBYNAME) || \ - defined(DEBUG_THREADING_GETADDRINFO) -/* If this is defined, provide tracing */ -#define TRACE(args) \ - do { trace_it("%u: ", __LINE__); trace_it args; } while (0) - -static void trace_it (const char *fmt, ...) -{ - static int do_trace = -1; - va_list args; - - if (do_trace == -1) { - const char *env = getenv("CURL_TRACE"); - do_trace = (env && atoi(env) > 0); - } - if (!do_trace) - return; - va_start (args, fmt); - vfprintf (stderr, fmt, args); - fflush (stderr); - va_end (args); -} -#else -#define TRACE(x) -#endif - -#ifdef DEBUG_THREADING_GETADDRINFO -static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai) -{ - TRACE(("dump_addrinfo:\n")); - for ( ; ai; ai = ai->ai_next) { - char buf [INET6_ADDRSTRLEN]; - - trace_it(" fam %2d, CNAME %s, ", - ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); - if (Curl_printable_address(ai, buf, sizeof(buf))) - trace_it("%s\n", buf); - else - trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError())); - } -} -#endif - -struct thread_data { - HANDLE thread_hnd; - unsigned thread_id; - DWORD thread_status; - curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */ - HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */ - HANDLE event_resolved; /* marks that the thread obtained the information */ - HANDLE event_thread_started; /* marks that the thread has initialized and - started */ - HANDLE mutex_terminate; /* serializes access to flag_terminate */ - HANDLE event_terminate; /* flag for thread to terminate instead of calling - callbacks */ -#ifdef CURLRES_IPV6 - struct addrinfo hints; -#endif -}; - -/* Data for synchronization between resolver thread and its parent */ -struct thread_sync_data { - HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */ - HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */ - HANDLE event_terminate; /* thread_data.event_terminate duplicate */ - char * hostname; /* hostname to resolve, Curl_async.hostname - duplicate */ -}; - -/* Destroy resolver thread synchronization data */ -static -void destroy_thread_sync_data(struct thread_sync_data * tsd) -{ - if (tsd->hostname) { - free(tsd->hostname); - tsd->hostname = NULL; - } - if (tsd->event_terminate) { - CloseHandle(tsd->event_terminate); - tsd->event_terminate = NULL; - } - if (tsd->mutex_terminate) { - CloseHandle(tsd->mutex_terminate); - tsd->mutex_terminate = NULL; - } - if (tsd->mutex_waiting) { - CloseHandle(tsd->mutex_waiting); - tsd->mutex_waiting = NULL; - } -} - -/* Initialize resolver thread synchronization data */ -static -BOOL init_thread_sync_data(struct thread_data * td, - char * hostname, - struct thread_sync_data * tsd) -{ - HANDLE curr_proc = GetCurrentProcess(); - - memset(tsd, 0, sizeof(*tsd)); - if (!DuplicateHandle(curr_proc, td->mutex_waiting, - curr_proc, &tsd->mutex_waiting, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - /* failed to duplicate the mutex, no point in continuing */ - destroy_thread_sync_data(tsd); - return FALSE; - } - if (!DuplicateHandle(curr_proc, td->mutex_terminate, - curr_proc, &tsd->mutex_terminate, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - /* failed to duplicate the mutex, no point in continuing */ - destroy_thread_sync_data(tsd); - return FALSE; - } - if (!DuplicateHandle(curr_proc, td->event_terminate, - curr_proc, &tsd->event_terminate, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - /* failed to duplicate the event, no point in continuing */ - destroy_thread_sync_data(tsd); - return FALSE; - } - /* Copying hostname string because original can be destroyed by parent - * thread during gethostbyname execution. - */ - tsd->hostname = strdup(hostname); - if (!tsd->hostname) { - /* Memory allocation failed */ - destroy_thread_sync_data(tsd); - return FALSE; - } - return TRUE; -} - -/* acquire resolver thread synchronization */ -static -BOOL acquire_thread_sync(struct thread_sync_data * tsd) -{ - /* is the thread initiator still waiting for us ? */ - if (WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) { - /* yes, it is */ - - /* Waiting access to event_terminate */ - if (WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) { - /* Something went wrong - now just ignoring */ - } - else { - if (WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) { - /* Parent thread signaled us to terminate. - * This means that all data in conn->async is now destroyed - * and we cannot use it. - */ - } - else { - return TRUE; - } - } - } - return FALSE; -} - -/* release resolver thread synchronization */ -static -void release_thread_sync(struct thread_sync_data * tsd) -{ - ReleaseMutex(tsd->mutex_terminate); -} - -#if defined(CURLRES_IPV4) -/* - * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback - * and then exits. - * - * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on - * it. - */ -static unsigned __stdcall gethostbyname_thread (void *arg) -{ - struct connectdata *conn = (struct connectdata*) arg; - struct thread_data *td = (struct thread_data*) conn->async.os_specific; - struct hostent *he; - int rc = 0; - - /* Duplicate the passed mutex and event handles. - * This allows us to use it even after the container gets destroyed - * due to a resolver timeout. - */ - struct thread_sync_data tsd = { 0,0,0,NULL }; - if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) { - /* thread synchronization data initialization failed */ - return (unsigned)-1; - } - - WSASetLastError (conn->async.status = NO_DATA); /* pending status */ - - /* Signaling that we have initialized all copies of data and handles we - need */ - SetEvent(td->event_thread_started); - - he = gethostbyname (tsd.hostname); - - /* is parent thread waiting for us and are we able to access conn members? */ - if (acquire_thread_sync(&tsd)) { - /* Mark that we have obtained the information, and that we are calling - * back with it. */ - SetEvent(td->event_resolved); - if (he) { - rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he); - } - else { - rc = Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL); - } - TRACE(("Winsock-error %d, addr %s\n", conn->async.status, - he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown")); - release_thread_sync(&tsd); - } - - /* clean up */ - destroy_thread_sync_data(&tsd); - - return (rc); - /* An implicit _endthreadex() here */ -} - -#elif defined(CURLRES_IPV6) - -/* - * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then - * exits. - * - * For builds without ARES, but with ENABLE_IPV6, create a resolver thread - * and wait on it. - */ -static unsigned __stdcall getaddrinfo_thread (void *arg) -{ - struct connectdata *conn = (struct connectdata*) arg; - struct thread_data *td = (struct thread_data*) conn->async.os_specific; - struct addrinfo *res; - char service [NI_MAXSERV]; - int rc; - struct addrinfo hints = td->hints; - - /* Duplicate the passed mutex handle. - * This allows us to use it even after the container gets destroyed - * due to a resolver timeout. - */ - struct thread_sync_data tsd = { 0,0,0,NULL }; - if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) { - /* thread synchronization data initialization failed */ - return -1; - } - - itoa(conn->async.port, service, 10); - - WSASetLastError(conn->async.status = NO_DATA); /* pending status */ - - /* Signaling that we have initialized all copies of data and handles we - need */ - SetEvent(td->event_thread_started); - - rc = getaddrinfo(tsd.hostname, service, &hints, &res); - - /* is parent thread waiting for us and are we able to access conn members? */ - if (acquire_thread_sync(&tsd)) { - /* Mark that we have obtained the information, and that we are calling - back with it. */ - SetEvent(td->event_resolved); - - if (rc == 0) { -#ifdef DEBUG_THREADING_GETADDRINFO - dump_addrinfo (conn, res); -#endif - rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res); - } - else { - rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL); - TRACE(("Winsock-error %d, no address\n", conn->async.status)); - } - release_thread_sync(&tsd); - } - - /* clean up */ - destroy_thread_sync_data(&tsd); - - return (rc); - /* An implicit _endthreadex() here */ -} -#endif - -/* - * Curl_destroy_thread_data() cleans up async resolver data and thread handle. - * Complementary of ares_destroy. - */ -void Curl_destroy_thread_data (struct Curl_async *async) -{ - if (async->hostname) - free(async->hostname); - - if (async->os_specific) { - struct thread_data *td = (struct thread_data*) async->os_specific; - curl_socket_t sock = td->dummy_sock; - - if (td->mutex_terminate && td->event_terminate) { - /* Signaling resolver thread to terminate */ - if (WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) { - SetEvent(td->event_terminate); - ReleaseMutex(td->mutex_terminate); - } - else { - /* Something went wrong - just ignoring it */ - } - } - - if (td->mutex_terminate) - CloseHandle(td->mutex_terminate); - if (td->event_terminate) - CloseHandle(td->event_terminate); - if (td->event_thread_started) - CloseHandle(td->event_thread_started); - - if (sock != CURL_SOCKET_BAD) - sclose(sock); - - /* destroy the synchronization objects */ - if (td->mutex_waiting) - CloseHandle(td->mutex_waiting); - td->mutex_waiting = NULL; - if (td->event_resolved) - CloseHandle(td->event_resolved); - - if (td->thread_hnd) - CloseHandle(td->thread_hnd); - - free(async->os_specific); - } - async->hostname = NULL; - async->os_specific = NULL; -} - -/* - * init_resolve_thread() starts a new thread that performs the actual - * resolve. This function returns before the resolve is done. - * - * Returns FALSE in case of failure, otherwise TRUE. - */ -static bool init_resolve_thread (struct connectdata *conn, - const char *hostname, int port, - const Curl_addrinfo *hints) -{ - struct thread_data *td = calloc(sizeof(*td), 1); - HANDLE thread_and_event[2] = {0}; - - if (!td) { - SetLastError(ENOMEM); - return FALSE; - } - - Curl_safefree(conn->async.hostname); - conn->async.hostname = strdup(hostname); - if (!conn->async.hostname) { - free(td); - SetLastError(ENOMEM); - return FALSE; - } - - conn->async.port = port; - conn->async.done = FALSE; - conn->async.status = 0; - conn->async.dns = NULL; - conn->async.os_specific = (void*) td; - td->dummy_sock = CURL_SOCKET_BAD; - - /* Create the mutex used to inform the resolver thread that we're - * still waiting, and take initial ownership. - */ - td->mutex_waiting = CreateMutex(NULL, TRUE, NULL); - if (td->mutex_waiting == NULL) { - Curl_destroy_thread_data(&conn->async); - SetLastError(EAGAIN); - return FALSE; - } - - /* Create the event that the thread uses to inform us that it's - * done resolving. Do not signal it. - */ - td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL); - if (td->event_resolved == NULL) { - Curl_destroy_thread_data(&conn->async); - SetLastError(EAGAIN); - return FALSE; - } - /* Create the mutex used to serialize access to event_terminated - * between us and resolver thread. - */ - td->mutex_terminate = CreateMutex(NULL, FALSE, NULL); - if (td->mutex_terminate == NULL) { - Curl_destroy_thread_data(&conn->async); - SetLastError(EAGAIN); - return FALSE; - } - /* Create the event used to signal thread that it should terminate. - */ - td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL); - if (td->event_terminate == NULL) { - Curl_destroy_thread_data(&conn->async); - SetLastError(EAGAIN); - return FALSE; - } - /* Create the event used by thread to inform it has initialized its own data. - */ - td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL); - if (td->event_thread_started == NULL) { - Curl_destroy_thread_data(&conn->async); - SetLastError(EAGAIN); - return FALSE; - } - -#ifdef _WIN32_WCE - td->thread_hnd = (HANDLE) CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) THREAD_FUNC, - conn, 0, &td->thread_id); -#else - td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC, - conn, 0, &td->thread_id); -#endif - -#ifdef CURLRES_IPV6 - curlassert(hints); - td->hints = *hints; -#else - (void) hints; -#endif - - if (!td->thread_hnd) { -#ifdef _WIN32_WCE - TRACE(("CreateThread() failed; %s\n", Curl_strerror(conn,GetLastError()))); -#else - SetLastError(errno); - TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno))); -#endif - Curl_destroy_thread_data(&conn->async); - return FALSE; - } - /* Waiting until the thread will initialize its data or it will exit due errors. - */ - thread_and_event[0] = td->thread_hnd; - thread_and_event[1] = td->event_thread_started; - if (WaitForMultipleObjects(sizeof(thread_and_event) / - sizeof(thread_and_event[0]), - (const HANDLE*)thread_and_event, FALSE, - INFINITE) == WAIT_FAILED) { - /* The resolver thread has been created, - * most probably it works now - ignoring this "minor" error - */ - } - /* This socket is only to keep Curl_resolv_fdset() and select() happy; - * should never become signalled for read/write since it's unbound but - * Windows needs atleast 1 socket in select(). - */ - td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0); - return TRUE; -} - - -/* - * Curl_wait_for_resolv() waits for a resolve to finish. This function should - * be avoided since using this risk getting the multi interface to "hang". - * - * If 'entry' is non-NULL, make it point to the resolved dns entry - * - * This is the version for resolves-in-a-thread. - */ -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - struct thread_data *td = (struct thread_data*) conn->async.os_specific; - struct SessionHandle *data = conn->data; - long timeout; - DWORD status, ticks; - CURLcode rc; - - curlassert (conn && td); - - /* now, see if there's a connect timeout or a regular timeout to - use instead of the default one */ - timeout = - conn->data->set.connecttimeout ? conn->data->set.connecttimeout : - conn->data->set.timeout ? conn->data->set.timeout : - CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */ - ticks = GetTickCount(); - - /* wait for the thread to resolve the name */ - status = WaitForSingleObject(td->event_resolved, 1000UL*timeout); - - /* mark that we are now done waiting */ - ReleaseMutex(td->mutex_waiting); - - /* close our handle to the mutex, no point in hanging on to it */ - CloseHandle(td->mutex_waiting); - td->mutex_waiting = NULL; - - /* close the event handle, it's useless now */ - CloseHandle(td->event_resolved); - td->event_resolved = NULL; - - /* has the resolver thread succeeded in resolving our query ? */ - if (status == WAIT_OBJECT_0) { - /* wait for the thread to exit, it's in the callback sequence */ - if (WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) { - TerminateThread(td->thread_hnd, 0); - conn->async.done = TRUE; - td->thread_status = (DWORD)-1; - TRACE(("%s() thread stuck?!, ", THREAD_NAME)); - } - else { - /* Thread finished before timeout; propagate Winsock error to this - * thread. 'conn->async.done = TRUE' is set in - * Curl_addrinfo4/6_callback(). - */ - WSASetLastError(conn->async.status); - GetExitCodeThread(td->thread_hnd, &td->thread_status); - TRACE(("%s() status %lu, thread retval %lu, ", - THREAD_NAME, status, td->thread_status)); - } - } - else { - conn->async.done = TRUE; - td->thread_status = (DWORD)-1; - TRACE(("%s() timeout, ", THREAD_NAME)); - } - - TRACE(("elapsed %lu ms\n", GetTickCount()-ticks)); - - if(entry) - *entry = conn->async.dns; - - rc = CURLE_OK; - - if (!conn->async.dns) { - /* a name was not resolved */ - if (td->thread_status == CURLE_OUT_OF_MEMORY) { - rc = CURLE_OUT_OF_MEMORY; - failf(data, "Could not resolve host: %s", curl_easy_strerror(rc)); - } - else if(conn->async.done) { - if(conn->bits.httpproxy) { - failf(data, "Could not resolve proxy: %s; %s", - conn->proxy.dispname, Curl_strerror(conn, conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_PROXY; - } - else { - failf(data, "Could not resolve host: %s; %s", - conn->host.name, Curl_strerror(conn, conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_HOST; - } - } - else if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) { - failf(data, "Resolving host timed out: %s", conn->host.name); - rc = CURLE_OPERATION_TIMEDOUT; - } - else - rc = CURLE_OPERATION_TIMEDOUT; - } - - Curl_destroy_thread_data(&conn->async); - - if(!conn->async.dns) - conn->bits.close = TRUE; - - return (rc); -} - -/* - * Curl_is_resolved() is called repeatedly to check if a previous name resolve - * request has completed. It should also make sure to time-out if the - * operation seems to take too long. - */ -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - *entry = NULL; - - if (conn->async.done) { - /* we're done */ - Curl_destroy_thread_data(&conn->async); - if (!conn->async.dns) { - TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n")); - return CURLE_COULDNT_RESOLVE_HOST; - } - *entry = conn->async.dns; - TRACE(("resolved okay, dns %p\n", *entry)); - } - return CURLE_OK; -} - -int Curl_resolv_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - const struct thread_data *td = - (const struct thread_data *) conn->async.os_specific; - - if (td && td->dummy_sock != CURL_SOCKET_BAD) { - if(numsocks) { - /* return one socket waiting for writable, even though this is just - a dummy */ - socks[0] = td->dummy_sock; - return GETSOCK_WRITESOCK(0); - } - } - return 0; -} - -#ifdef CURLRES_IPV4 -/* - * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6. - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - struct hostent *h = NULL; - struct SessionHandle *data = conn->data; - in_addr_t in; - - *waitp = 0; /* don't wait, we act synchronously */ - - in = inet_addr(hostname); - if (in != CURL_INADDR_NONE) - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(in, hostname, port); - - /* fire up a new resolver thread! */ - if (init_resolve_thread(conn, hostname, port, NULL)) { - *waitp = TRUE; /* please wait for the response */ - return NULL; - } - - /* fall-back to blocking version */ - infof(data, "init_resolve_thread() failed for %s; %s\n", - hostname, Curl_strerror(conn,GetLastError())); - - h = gethostbyname(hostname); - if (!h) { - infof(data, "gethostbyname(2) failed for %s:%d; %s\n", - hostname, port, Curl_strerror(conn,WSAGetLastError())); - return NULL; - } - return Curl_he2ai(h, port); -} -#endif /* CURLRES_IPV4 */ - -#ifdef CURLRES_IPV6 -/* - * Curl_getaddrinfo() - for Windows threading IPv6 enabled - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - struct addrinfo hints, *res; - int error; - char sbuf[NI_MAXSERV]; - curl_socket_t s; - int pf; - struct SessionHandle *data = conn->data; - - *waitp = FALSE; /* default to synch response */ - - /* see if we have an IPv6 stack */ - s = socket(PF_INET6, SOCK_DGRAM, 0); - if (s == CURL_SOCKET_BAD) { - /* Some non-IPv6 stacks have been found to make very slow name resolves - * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if - * the stack seems to be a non-ipv6 one. */ - - pf = PF_INET; - } - else { - /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest - * possible checks. And close the socket again. - */ - sclose(s); - - /* - * Check if a more limited name resolve has been requested. - */ - switch(data->set.ip_version) { - case CURL_IPRESOLVE_V4: - pf = PF_INET; - break; - case CURL_IPRESOLVE_V6: - pf = PF_INET6; - break; - default: - pf = PF_UNSPEC; - break; - } - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = pf; - hints.ai_socktype = conn->socktype; -#if 0 /* removed nov 8 2005 before 7.15.1 */ - hints.ai_flags = AI_CANONNAME; -#endif - itoa(port, sbuf, 10); - - /* fire up a new resolver thread! */ - if (init_resolve_thread(conn, hostname, port, &hints)) { - *waitp = TRUE; /* please wait for the response */ - return NULL; - } - - /* fall-back to blocking version */ - infof(data, "init_resolve_thread() failed for %s; %s\n", - hostname, Curl_strerror(conn,GetLastError())); - - error = getaddrinfo(hostname, sbuf, &hints, &res); - if (error) { - infof(data, "getaddrinfo() failed for %s:%d; %s\n", - hostname, port, Curl_strerror(conn,WSAGetLastError())); - return NULL; - } - return res; -} -#endif /* CURLRES_IPV6 */ -#endif /* CURLRES_THREADED */ diff --git a/Utilities/cmcurl/http.c b/Utilities/cmcurl/http.c deleted file mode 100644 index 5405aac..0000000 --- a/Utilities/cmcurl/http.c +++ /dev/null @@ -1,2422 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifdef HAVE_TIME_H -#ifdef TIME_WITH_SYS_TIME -#include -#endif -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ -#include "formdata.h" -#include "progress.h" -#include "base64.h" -#include "cookie.h" -#include "strequal.h" -#include "sslgen.h" -#include "http_digest.h" -#include "http_ntlm.h" -#include "http_negotiate.h" -#include "url.h" -#include "share.h" -#include "hostip.h" -#include "http.h" -#include "memory.h" -#include "select.h" -#include "parsedate.h" /* for the week day and month names */ -#include "strtoofft.h" -#include "multiif.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * checkheaders() checks the linked list of custom HTTP headers for a - * particular header (prefix). - * - * Returns a pointer to the first matching header or NULL if none matched. - */ -static char *checkheaders(struct SessionHandle *data, const char *thisheader) -{ - struct curl_slist *head; - size_t thislen = strlen(thisheader); - - for(head = data->set.headers; head; head=head->next) { - if(strnequal(head->data, thisheader, thislen)) - return head->data; - } - return NULL; -} - -/* - * Curl_output_basic() sets up an Authorization: header (or the proxy version) - * for HTTP Basic authentication. - * - * Returns CURLcode. - */ -static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy) -{ - char *authorization; - struct SessionHandle *data=conn->data; - char **userp; - char *user; - char *pwd; - - if(proxy) { - userp = &conn->allocptr.proxyuserpwd; - user = conn->proxyuser; - pwd = conn->proxypasswd; - } - else { - userp = &conn->allocptr.userpwd; - user = conn->user; - pwd = conn->passwd; - } - - snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); - if(Curl_base64_encode(data, data->state.buffer, - strlen(data->state.buffer), - &authorization) > 0) { - if(*userp) - free(*userp); - *userp = aprintf( "%sAuthorization: Basic %s\r\n", - proxy?"Proxy-":"", - authorization); - free(authorization); - } - else - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; -} - -/* pickoneauth() selects the most favourable authentication method from the - * ones available and the ones we want. - * - * return TRUE if one was picked - */ -static bool pickoneauth(struct auth *pick) -{ - bool picked; - /* only deal with authentication we want */ - long avail = pick->avail & pick->want; - picked = TRUE; - - /* The order of these checks is highly relevant, as this will be the order - of preference in case of the existence of multiple accepted types. */ - if(avail & CURLAUTH_GSSNEGOTIATE) - pick->picked = CURLAUTH_GSSNEGOTIATE; - else if(avail & CURLAUTH_DIGEST) - pick->picked = CURLAUTH_DIGEST; - else if(avail & CURLAUTH_NTLM) - pick->picked = CURLAUTH_NTLM; - else if(avail & CURLAUTH_BASIC) - pick->picked = CURLAUTH_BASIC; - else { - pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ - picked = FALSE; - } - pick->avail = CURLAUTH_NONE; /* clear it here */ - - return picked; -} - -/* - * perhapsrewind() - * - * 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 perhapsrewind(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - struct HTTP *http = data->reqdata.proto.http; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - 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; - - bytessent = http->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 { - /* figure out how much data we are expected to send */ - switch(data->set.httpreq) { - case HTTPREQ_POST: - if(data->set.postfieldsize != -1) - expectsend = data->set.postfieldsize; - break; - case HTTPREQ_PUT: - if(data->set.infilesize != -1) - expectsend = data->set.infilesize; - break; - case HTTPREQ_POST_FORM: - expectsend = http->postsize; - break; - default: - break; - } - } - - conn->bits.rewindaftersend = FALSE; /* default */ - - if((expectsend == -1) || (expectsend > bytessent)) { - /* There is still data left to send */ - if((data->state.authproxy.picked == CURLAUTH_NTLM) || - (data->state.authhost.picked == CURLAUTH_NTLM)) { - if(((expectsend - bytessent) < 2000) || - (conn->ntlm.state != NTLMSTATE_NONE)) { - /* 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->bits.rewindaftersend = TRUE; - - 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 %" FORMAT_OFF_T - " bytes\n", (curl_off_t)(expectsend - bytessent)); - } - - /* This is not NTLM or NTLM with many bytes left to send: close - */ - conn->bits.close = TRUE; - k->size = 0; /* don't download any more than 0 bytes */ - } - - if(bytessent) - return Curl_readrewind(conn); - - return CURLE_OK; -} - -/* - * Curl_http_auth_act() gets called when a all HTTP headers have been received - * and it checks what authentication methods that are available and decides - * which one (if any) to use. It will set 'newurl' if an auth metod was - * picked. - */ - -CURLcode Curl_http_auth_act(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - bool pickhost = FALSE; - bool pickproxy = FALSE; - CURLcode code = CURLE_OK; - - if(100 == data->reqdata.keep.httpcode) - /* this is a transient response code, ignore */ - return CURLE_OK; - - if(data->state.authproblem) - return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; - - if(conn->bits.user_passwd && - ((data->reqdata.keep.httpcode == 401) || - (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) { - pickhost = pickoneauth(&data->state.authhost); - if(!pickhost) - data->state.authproblem = TRUE; - } - if(conn->bits.proxy_user_passwd && - ((data->reqdata.keep.httpcode == 407) || - (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) { - pickproxy = pickoneauth(&data->state.authproxy); - if(!pickproxy) - data->state.authproblem = TRUE; - } - - if(pickhost || pickproxy) { - data->reqdata.newurl = strdup(data->change.url); /* clone URL */ - - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD) && - !conn->bits.rewindaftersend) { - code = perhapsrewind(conn); - if(code) - return code; - } - } - - else if((data->reqdata.keep.httpcode < 300) && - (!data->state.authhost.done) && - conn->bits.authneg) { - /* no (known) authentication available, - authentication is not "done" yet and - no authentication seems to be required and - we didn't try HEAD or GET */ - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD)) { - data->reqdata.newurl = strdup(data->change.url); /* clone URL */ - data->state.authhost.done = TRUE; - } - } - if (Curl_http_should_fail(conn)) { - failf (data, "The requested URL returned error: %d", - data->reqdata.keep.httpcode); - code = CURLE_HTTP_RETURNED_ERROR; - } - - return code; -} - -/** - * Curl_http_output_auth() setups the authentication headers for the - * host/proxy and the correct authentication - * method. conn->data->state.authdone is set to TRUE when authentication is - * done. - * - * @param conn all information about the current connection - * @param request pointer to the request keyword - * @param path pointer to the requested path - * @param proxytunnel boolean if this is the request setting up a "proxy - * tunnel" - * - * @returns CURLcode - */ -static CURLcode -Curl_http_output_auth(struct connectdata *conn, - char *request, - char *path, - bool proxytunnel) /* TRUE if this is the request setting - up the proxy tunnel */ -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *auth=NULL; - struct auth *authhost; - struct auth *authproxy; - - curlassert(data); - - authhost = &data->state.authhost; - authproxy = &data->state.authproxy; - - if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || - conn->bits.user_passwd) - /* continue please */ ; - else { - authhost->done = TRUE; - authproxy->done = TRUE; - return CURLE_OK; /* no authentication with no user or password */ - } - - 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'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'll be used instantly. */ - authproxy->picked = authproxy->want; - - /* Send proxy authentication header if needed */ - if (conn->bits.httpproxy && - (conn->bits.tunnel_proxy == proxytunnel)) { -#ifdef USE_NTLM - if(authproxy->picked == CURLAUTH_NTLM) { - auth=(char *)"NTLM"; - result = Curl_output_ntlm(conn, TRUE); - if(result) - return result; - } - else -#endif - if(authproxy->picked == CURLAUTH_BASIC) { - /* Basic */ - if(conn->bits.proxy_user_passwd && - !checkheaders(data, "Proxy-authorization:")) { - auth=(char *)"Basic"; - result = Curl_output_basic(conn, TRUE); - if(result) - return result; - } - /* NOTE: Curl_output_basic() should set 'done' TRUE, as the other auth - functions work that way */ - authproxy->done = TRUE; - } -#ifndef CURL_DISABLE_CRYPTO_AUTH - else if(authproxy->picked == CURLAUTH_DIGEST) { - auth=(char *)"Digest"; - result = Curl_output_digest(conn, - TRUE, /* proxy */ - (unsigned char *)request, - (unsigned char *)path); - if(result) - return result; - } -#endif - if(auth) { - infof(data, "Proxy auth using %s with user '%s'\n", - auth, conn->proxyuser?conn->proxyuser:""); - authproxy->multi = (bool)(!authproxy->done); - } - else - authproxy->multi = FALSE; - } - else - /* we have no proxy so let's pretend we're done authenticating - with it */ - authproxy->done = TRUE; - - /* To prevent the user+password to get sent to other than the original - host due to a location-follow, we do some weirdo checks here */ - if(!data->state.this_is_a_follow || - conn->bits.netrc || - !data->state.first_host || - curl_strequal(data->state.first_host, conn->host.name) || - data->set.http_disable_hostname_check_before_authentication) { - - /* Send web authentication header if needed */ - { - auth = NULL; -#ifdef HAVE_GSSAPI - if((authhost->picked == CURLAUTH_GSSNEGOTIATE) && - data->state.negotiate.context && - !GSS_ERROR(data->state.negotiate.status)) { - auth=(char *)"GSS-Negotiate"; - result = Curl_output_negotiate(conn); - if (result) - return result; - authhost->done = TRUE; - } - else -#endif -#ifdef USE_NTLM - if(authhost->picked == CURLAUTH_NTLM) { - auth=(char *)"NTLM"; - result = Curl_output_ntlm(conn, FALSE); - if(result) - return result; - } - else -#endif - { -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(authhost->picked == CURLAUTH_DIGEST) { - auth=(char *)"Digest"; - result = Curl_output_digest(conn, - FALSE, /* not a proxy */ - (unsigned char *)request, - (unsigned char *)path); - if(result) - return result; - } else -#endif - if(authhost->picked == CURLAUTH_BASIC) { - if(conn->bits.user_passwd && - !checkheaders(data, "Authorization:")) { - auth=(char *)"Basic"; - result = Curl_output_basic(conn, FALSE); - if(result) - return result; - } - /* basic is always ready */ - authhost->done = TRUE; - } - } - if(auth) { - infof(data, "Server auth using %s with user '%s'\n", - auth, conn->user); - - authhost->multi = (bool)(!authhost->done); - } - else - authhost->multi = FALSE; - } - } - else - authhost->done = TRUE; - - return result; -} - - -/* - * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: - * headers. They are dealt with both in the transfer.c main loop and in the - * proxy CONNECT loop. - */ - -CURLcode Curl_http_input_auth(struct connectdata *conn, - int httpcode, - char *header) /* the first non-space */ -{ - /* - * This resource requires authentication - */ - struct SessionHandle *data = conn->data; - - long *availp; - char *start; - struct auth *authp; - - if (httpcode == 407) { - start = header+strlen("Proxy-authenticate:"); - availp = &data->info.proxyauthavail; - authp = &data->state.authproxy; - } - else { - start = header+strlen("WWW-Authenticate:"); - availp = &data->info.httpauthavail; - authp = &data->state.authhost; - } - - /* pass all white spaces */ - while(*start && ISSPACE(*start)) - start++; - - /* - * Here we check if we want the specific single authentication (using ==) and - * if we do, we initiate usage of it. - * - * If the provided authentication is wanted as one out of several accepted - * types (using &), we OR this authentication type to the authavail - * variable. - */ - -#ifdef HAVE_GSSAPI - if (checkprefix("GSS-Negotiate", start) || - checkprefix("Negotiate", start)) { - *availp |= CURLAUTH_GSSNEGOTIATE; - authp->avail |= CURLAUTH_GSSNEGOTIATE; - if(authp->picked == CURLAUTH_GSSNEGOTIATE) { - /* if exactly this is wanted, go */ - int neg = Curl_input_negotiate(conn, start); - if (neg == 0) { - data->reqdata.newurl = strdup(data->change.url); - data->state.authproblem = (data->reqdata.newurl == NULL); - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - } - else -#endif -#ifdef USE_NTLM - /* NTLM support requires the SSL crypto libs */ - if(checkprefix("NTLM", start)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM) { - /* NTLM authentication is picked and activated */ - CURLntlm ntlm = - Curl_input_ntlm(conn, (bool)(httpcode == 407), start); - - if(CURLNTLM_BAD != ntlm) - data->state.authproblem = FALSE; - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(checkprefix("Digest", start)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { - infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { - CURLdigest dig; - *availp |= CURLAUTH_DIGEST; - authp->avail |= CURLAUTH_DIGEST; - - /* We call this function on input Digest headers even if Digest - * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are gonna use Digest. */ - dig = Curl_input_digest(conn, (bool)(httpcode == 407), start); - - if(CURLDIGEST_FINE != dig) { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - } - else -#endif - if(checkprefix("Basic", start)) { - *availp |= CURLAUTH_BASIC; - authp->avail |= CURLAUTH_BASIC; - if(authp->picked == CURLAUTH_BASIC) { - /* We asked for Basic authentication but got a 40X back - anyway, which basicly means our name+password isn't - valid. */ - authp->avail = CURLAUTH_NONE; - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - - return CURLE_OK; -} - -/** - * Curl_http_should_fail() determines whether an HTTP response has gotten us - * into an error state or not. - * - * @param conn all information about the current connection - * - * @retval 0 communications should continue - * - * @retval 1 communications should not continue - */ -int Curl_http_should_fail(struct connectdata *conn) -{ - struct SessionHandle *data; - struct Curl_transfer_keeper *k; - - curlassert(conn); - data = conn->data; - curlassert(data); - - /* - ** For readability - */ - k = &data->reqdata.keep; - - /* - ** If we haven't been asked to fail on error, - ** don't fail. - */ - if (!data->set.http_fail_on_error) - return 0; - - /* - ** Any code < 400 is never terminal. - */ - if (k->httpcode < 400) - return 0; - - if (data->reqdata.resume_from && - (data->set.httpreq==HTTPREQ_GET) && - (k->httpcode == 416)) { - /* "Requested Range Not Satisfiable", just proceed and - pretend this is no error */ - return 0; - } - - /* - ** Any code >= 400 that's not 401 or 407 is always - ** a terminal error - */ - if ((k->httpcode != 401) && - (k->httpcode != 407)) - return 1; - - /* - ** All we have left to deal with is 401 and 407 - */ - curlassert((k->httpcode == 401) || (k->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'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. - */ -#if 0 /* set to 1 when debugging this functionality */ - infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage); - infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant); - infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail); - infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode); - infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone); - infof(data,"%s: newurl = %s\n",__FUNCTION__,data->reqdata.newurl ? data->reqdata.newurl : "(null)"); - infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem); -#endif - - /* - ** Either we're not authenticating, or we're supposed to - ** be authenticating something else. This is an error. - */ - if((k->httpcode == 401) && !conn->bits.user_passwd) - return TRUE; - if((k->httpcode == 407) && !conn->bits.proxy_user_passwd) - return TRUE; - - return data->state.authproblem; -} - -/* - * 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 connectdata *conn = (struct connectdata *)userp; - struct HTTP *http = conn->data->reqdata.proto.http; - size_t fullsize = size * nitems; - - if(0 == http->postsize) - /* nothing to return */ - return 0; - - /* make sure that a HTTP request is never sent away chunked! */ - conn->bits.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST); - - 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; - conn->fread = http->backup.fread; - conn->fread_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; -} - -/* ------------------------------------------------------------------------- */ -/* - * The add_buffer series of functions are used to build one large memory chunk - * from repeated function invokes. Used so that the entire HTTP request can - * be sent in one go. - */ - -struct send_buffer { - char *buffer; - size_t size_max; - size_t size_used; -}; -typedef struct send_buffer send_buffer; - -static CURLcode add_custom_headers(struct connectdata *conn, - send_buffer *req_buffer); -static CURLcode - add_buffer(send_buffer *in, const void *inptr, size_t size); - -/* - * add_buffer_init() sets up and returns a fine buffer struct - */ -static -send_buffer *add_buffer_init(void) -{ - send_buffer *blonk; - blonk=(send_buffer *)malloc(sizeof(send_buffer)); - if(blonk) { - memset(blonk, 0, sizeof(send_buffer)); - return blonk; - } - return NULL; /* failed, go home */ -} - -/* - * add_buffer_send() sends a header buffer and frees all associated memory. - * Body data may be appended to the header data if desired. - * - * Returns CURLcode - */ -static -CURLcode add_buffer_send(send_buffer *in, - struct connectdata *conn, - long *bytes_written, /* add the number of sent - bytes to this counter */ - size_t included_body_bytes, /* how much of the buffer - contains body data (for log tracing) */ - int socketindex) - -{ - ssize_t amount; - CURLcode res; - char *ptr; - size_t size; - struct HTTP *http = conn->data->reqdata.proto.http; - size_t sendsize; - curl_socket_t sockfd; - - curlassert(socketindex <= SECONDARYSOCKET); - - sockfd = conn->sock[socketindex]; - - /* 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 = in->buffer; - size = in->size_used; - -#ifdef CURL_DOES_CONVERSIONS - if(size - included_body_bytes > 0) { - res = Curl_convert_to_network(conn->data, ptr, size - included_body_bytes); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - /* conversion failed, free memory and return to the caller */ - if(in->buffer) - free(in->buffer); - free(in); - return res; - } - } -#endif /* CURL_DOES_CONVERSIONS */ - - if(conn->protocol & PROT_HTTPS) { - /* We never send more than CURL_MAX_WRITE_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. - */ - - sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE: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. - */ - memcpy(conn->data->state.uploadbuffer, ptr, sendsize); - ptr = conn->data->state.uploadbuffer; - } - else - sendsize = size; - - res = Curl_write(conn, sockfd, ptr, sendsize, &amount); - - if(CURLE_OK == res) { - - if(conn->data->set.verbose) { - /* this data _may_ contain binary stuff */ - Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, - (size_t)(amount-included_body_bytes), conn); - if (included_body_bytes) - Curl_debug(conn->data, CURLINFO_DATA_OUT, - ptr+amount-included_body_bytes, - (size_t)included_body_bytes, conn); - } - - *bytes_written += amount; - - if(http) { - 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 = in->buffer + amount; - - /* backup the currently set pointers */ - http->backup.fread = conn->fread; - http->backup.fread_in = conn->fread_in; - http->backup.postdata = http->postdata; - http->backup.postsize = http->postsize; - - /* set the new pointers for the request-sending */ - conn->fread = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; - http->postdata = ptr; - http->postsize = (curl_off_t)size; - - http->send_buffer = in; - 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; - else - conn->writechannel_inuse = FALSE; - } - } - if(in->buffer) - free(in->buffer); - free(in); - - return res; -} - - -/* - * add_bufferf() add the formatted input to the buffer. - */ -static -CURLcode add_bufferf(send_buffer *in, const char *fmt, ...) -{ - char *s; - va_list ap; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* this allocs a new string to append */ - va_end(ap); - - if(s) { - CURLcode result = add_buffer(in, s, strlen(s)); - free(s); - if(CURLE_OK == result) - return CURLE_OK; - } - /* If we failed, we cleanup the whole buffer and return error */ - if(in->buffer) - free(in->buffer); - free(in); - return CURLE_OUT_OF_MEMORY; -} - -/* - * add_buffer() appends a memory chunk to the existing buffer - */ -static -CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size) -{ - char *new_rb; - size_t new_size; - - if(!in->buffer || - ((in->size_used + size) > (in->size_max - 1))) { - new_size = (in->size_used+size)*2; - if(in->buffer) - /* we have a buffer, enlarge the existing one */ - new_rb = (char *)realloc(in->buffer, new_size); - else - /* create a new buffer */ - new_rb = (char *)malloc(new_size); - - if(!new_rb) - return CURLE_OUT_OF_MEMORY; - - in->buffer = new_rb; - in->size_max = new_size; - } - memcpy(&in->buffer[in->size_used], inptr, size); - - in->size_used += size; - - return CURLE_OK; -} - -/* end of the add_buffer functions */ -/* ------------------------------------------------------------------------- */ - -/* - * Curl_compareheader() - * - * Returns TRUE if 'headerline' contains the 'header' with given 'content'. - * Pass headers WITH the colon. - */ -bool -Curl_compareheader(char *headerline, /* line to check */ - const char *header, /* header keyword _with_ colon */ - const char *content) /* content string to find */ -{ - /* RFC2616, section 4.2 says: "Each header field consists of a name followed - * by a colon (":") and the field value. Field names are case-insensitive. - * The field value MAY be preceded by any amount of LWS, though a single SP - * is preferred." */ - - size_t hlen = strlen(header); - size_t clen; - size_t len; - char *start; - char *end; - - if(!strnequal(headerline, header, hlen)) - return FALSE; /* doesn't start with header */ - - /* pass the header */ - start = &headerline[hlen]; - - /* pass all white spaces */ - while(*start && ISSPACE(*start)) - start++; - - /* find the end of the header line */ - end = strchr(start, '\r'); /* lines end with CRLF */ - if(!end) { - /* in case there's a non-standard compliant line here */ - end = strchr(start, '\n'); - - if(!end) - /* hm, there's no line ending here, use the zero byte! */ - end = strchr(start, '\0'); - } - - len = end-start; /* length of the content part of the input line */ - clen = strlen(content); /* length of the word to find */ - - /* find the content string in the rest of the line */ - for(;len>=clen;len--, start++) { - if(strnequal(start, content, clen)) - return TRUE; /* match! */ - } - - return FALSE; /* no match */ -} - -/* - * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This - * function will issue the necessary commands to get a seamless tunnel through - * this proxy. After that, the socket can be used just as a normal socket. - * - * This badly needs to be rewritten. CONNECT should be sent and dealt with - * like any ordinary HTTP request, and not specially crafted like this. This - * function only remains here like this for now since the rewrite is a bit too - * much work to do at the moment. - * - * This function is BLOCKING which is nasty for all multi interface using apps. - */ - -CURLcode Curl_proxyCONNECT(struct connectdata *conn, - int sockindex, - char *hostname, - int remote_port) -{ - int subversion=0; - struct SessionHandle *data=conn->data; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - CURLcode result; - int res; - size_t nread; /* total size read */ - int perline; /* count bytes per line */ - int keepon=TRUE; - ssize_t gotbytes; - char *ptr; - long timeout = - data->set.timeout?data->set.timeout:3600; /* in seconds */ - char *line_start; - char *host_port; - curl_socket_t tunnelsocket = conn->sock[sockindex]; - send_buffer *req_buffer; - curl_off_t cl=0; - bool closeConnection = FALSE; - -#define SELECT_OK 0 -#define SELECT_ERROR 1 -#define SELECT_TIMEOUT 2 - int error = SELECT_OK; - - infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); - conn->bits.proxy_connect_closed = FALSE; - - do { - if(data->reqdata.newurl) { - /* 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. */ - free(data->reqdata.newurl); - data->reqdata.newurl = NULL; - } - - /* initialize a dynamic send-buffer */ - req_buffer = add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - - host_port = aprintf("%s:%d", hostname, remote_port); - if(!host_port) - return CURLE_OUT_OF_MEMORY; - - /* Setup the proxy-authorization header, if any */ - result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE); - - if(CURLE_OK == result) { - char *host=(char *)""; - const char *proxyconn=""; - const char *useragent=""; - - if(!checkheaders(data, "Host:")) { - host = aprintf("Host: %s\r\n", host_port); - if(!host) - result = CURLE_OUT_OF_MEMORY; - } - if(!checkheaders(data, "Proxy-Connection:")) - proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - - if(!checkheaders(data, "User-Agent:") && data->set.useragent) - useragent = conn->allocptr.uagent; - - if(CURLE_OK == result) { - /* Send the connect request to the proxy */ - /* BLOCKING */ - result = - add_bufferf(req_buffer, - "CONNECT %s:%d HTTP/1.0\r\n" - "%s" /* Host: */ - "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ - hostname, remote_port, - host, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - useragent, - proxyconn); - - if(CURLE_OK == result) - result = add_custom_headers(conn, req_buffer); - - if(host && *host) - free(host); - - if(CURLE_OK == result) - /* CRLF terminate the request */ - result = add_bufferf(req_buffer, "\r\n"); - - if(CURLE_OK == result) - /* Now send off the request */ - result = add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, sockindex); - } - if(result) - failf(data, "Failed sending CONNECT to proxy"); - } - free(host_port); - if(result) - return result; - - ptr=data->state.buffer; - line_start = ptr; - - nread=0; - perline=0; - keepon=TRUE; - - while((nreadnow)/1000; /* spent time */ - if(check <=0 ) { - failf(data, "Proxy CONNECT aborted due to timeout"); - error = SELECT_TIMEOUT; /* already too little time */ - break; - } - - /* timeout each second and check the timeout */ - switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD, 1000)) { - case -1: /* select() error, stop reading */ - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted due to select() error"); - break; - case 0: /* timeout */ - break; - default: - res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); - if(res< 0) - /* EWOULDBLOCK */ - continue; /* go loop yourself */ - else if(res) - keepon = FALSE; - else if(gotbytes <= 0) { - keepon = FALSE; - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted"); - } - else { - /* - * We got a whole chunk of data, which can be anything from one byte - * to a set of lines and possibly just a piece of the last line. - */ - int i; - - nread += gotbytes; - - if(keepon > TRUE) { - /* This means we are currently ignoring a response-body, so we - simply count down our counter and make sure to break out of the - loop when we're done! */ - cl -= gotbytes; - if(cl<=0) { - keepon = FALSE; - break; - } - } - else - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; /* amount of bytes in this line so far */ - if(*ptr=='\n') { - char letter; - int writetype; - - /* output debug if that is requested */ - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - line_start, (size_t)perline, conn); - - /* send the header to the callback */ - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - result = Curl_client_write(conn, writetype, line_start, perline); - if(result) - return result; - - /* 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.*/ - - if(('\r' == line_start[0]) || - ('\n' == line_start[0])) { - /* end of response-headers from the proxy */ - if(cl && (407 == k->httpcode) && !data->state.authproblem) { - /* If we get a 407 response code with content length when we - * have no auth problem, we must ignore the whole - * response-body */ - keepon = 2; - infof(data, "Ignore %" FORMAT_OFF_T - " bytes of response-body\n", cl); - cl -= (gotbytes - i);/* remove the remaining chunk of what - we already read */ - if(cl<=0) - /* if the whole thing was already read, we are done! */ - keepon=FALSE; - } - else - keepon = FALSE; - break; /* breaks out of for-loop, not switch() */ - } - - /* keep a backup of the position we are about to blank */ - letter = line_start[perline]; - line_start[perline]=0; /* zero terminate the buffer */ - if((checkprefix("WWW-Authenticate:", line_start) && - (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", line_start) && - (407 == k->httpcode))) { - result = Curl_http_input_auth(conn, k->httpcode, line_start); - if(result) - return result; - } - else if(checkprefix("Content-Length:", line_start)) { - cl = curlx_strtoofft(line_start + strlen("Content-Length:"), - NULL, 10); - } - else if(Curl_compareheader(line_start, - "Connection:", "close")) - closeConnection = TRUE; - else if(2 == sscanf(line_start, "HTTP/1.%d %d", - &subversion, - &k->httpcode)) { - /* store the HTTP code from the proxy */ - data->info.httpproxycode = k->httpcode; - } - /* put back the letter we blanked out before */ - line_start[perline]= letter; - - perline=0; /* line starts over here */ - line_start = ptr+1; /* this skips the zero byte we wrote */ - } - } - } - break; - } /* switch */ - } /* while there's buffer left and loop is requested */ - - if(error) - return CURLE_RECV_ERROR; - - if(data->info.httpproxycode != 200) - /* Deal with the possibly already received authenticate - headers. 'newurl' is set to a new URL if we must loop. */ - Curl_http_auth_act(conn); - - if (closeConnection && data->reqdata.newurl) { - /* Connection closed by server. Don't use it anymore */ - sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - break; - } - } while(data->reqdata.newurl); - - if(200 != k->httpcode) { - failf(data, "Received HTTP code %d from proxy after CONNECT", - k->httpcode); - - if (closeConnection && data->reqdata.newurl) - conn->bits.proxy_connect_closed = TRUE; - - return CURLE_RECV_ERROR; - } - - /* If a proxy-authorization header was used for the proxy, then we should - 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(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = NULL; - - data->state.authproxy.done = TRUE; - - infof (data, "Proxy replied OK to CONNECT request\n"); - return CURLE_OK; -} - -/* - * Curl_http_connect() performs HTTP stuff to do at connect-time, called from - * the generic Curl_connect(). - */ -CURLcode Curl_http_connect(struct connectdata *conn, bool *done) -{ - struct SessionHandle *data; - CURLcode result; - - data=conn->data; - - /* If we are not using a proxy and we want a secure connection, perform SSL - * initialization & connection now. If using a proxy with https, then we - * must tell the proxy to CONNECT to the host we want to talk to. Only - * after the connect has occurred, can we start talking SSL - */ - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - - /* either SSL over proxy, or explicitly asked for */ - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, - conn->remote_port); - if(CURLE_OK != result) - return result; - } - - if(!data->state.this_is_a_follow) { - /* this is not a followed location, get the original host name */ - if (data->state.first_host) - /* Free to avoid leaking memory on multiple requests*/ - free(data->state.first_host); - - data->state.first_host = strdup(conn->host.name); - if(!data->state.first_host) - return CURLE_OUT_OF_MEMORY; - } - - if(conn->protocol & PROT_HTTPS) { - /* perform SSL initialization */ - if(data->state.used_interface == Curl_if_multi) { - result = Curl_https_connecting(conn, done); - if(result) - return result; - } - else { - /* BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - *done = TRUE; - } - } - else { - *done = TRUE; - } - - return CURLE_OK; -} - -CURLcode Curl_https_connecting(struct connectdata *conn, bool *done) -{ - CURLcode result; - curlassert(conn->protocol & PROT_HTTPS); - - /* perform SSL initialization for this socket */ - result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done); - if(result) - return result; - - return CURLE_OK; -} - -#ifdef USE_SSLEAY -/* This function is OpenSSL-specific. It should be made to query the generic - SSL layer instead. */ -int Curl_https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if (conn->protocol & PROT_HTTPS) { - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; - - if(!numsocks) - return GETSOCK_BLANK; - - if (connssl->connecting_state == ssl_connect_2_writing) { - /* write mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); - } - else if (connssl->connecting_state == ssl_connect_2_reading) { - /* read mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0); - } - } - return CURLE_OK; -} -#else -#ifdef USE_GNUTLS -int Curl_https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; - return GETSOCK_BLANK; -} -#endif -#endif - -/* - * Curl_http_done() gets called from Curl_done() after a single HTTP request - * has been performed. - */ - -CURLcode Curl_http_done(struct connectdata *conn, - CURLcode status, bool premature) -{ - struct SessionHandle *data = conn->data; - struct HTTP *http =data->reqdata.proto.http; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - (void)premature; /* not used */ - - /* set the proper values (possibly modified on POST) */ - conn->fread = data->set.fread; /* restore */ - conn->fread_in = data->set.in; /* restore */ - - if (http == NULL) - return CURLE_OK; - - if(http->send_buffer) { - send_buffer *buff = http->send_buffer; - - free(buff->buffer); - free(buff); - http->send_buffer = NULL; /* clear the pointer */ - } - - if(HTTPREQ_POST_FORM == data->set.httpreq) { - k->bytecount = http->readbytecount + http->writebytecount; - - Curl_formclean(&http->sendit); /* Now free that whole lot */ - if(http->form.fp) { - /* a file being uploaded was left opened, close it! */ - fclose(http->form.fp); - http->form.fp = NULL; - } - } - else if(HTTPREQ_PUT == data->set.httpreq) - k->bytecount = http->readbytecount + http->writebytecount; - - if (status != CURLE_OK) - return (status); - - if(!conn->bits.retry && - ((http->readbytecount + - conn->headerbytecount - - conn->deductheadercount)) <= 0) { - /* 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"); - return CURLE_GOT_NOTHING; - } - - return CURLE_OK; -} - -/* check and possibly add an Expect: header */ -static CURLcode expect100(struct SessionHandle *data, - send_buffer *req_buffer) -{ - CURLcode result = CURLE_OK; - data->state.expect100header = FALSE; /* default to false unless it is set - to TRUE below */ - if((data->set.httpversion != CURL_HTTP_VERSION_1_0) && - !checkheaders(data, "Expect:")) { - /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect: - 100-continue to the headers which actually speeds up post - operations (as there is one packet coming back from the web - server) */ - result = add_bufferf(req_buffer, - "Expect: 100-continue\r\n"); - if(result == CURLE_OK) - data->state.expect100header = TRUE; - } - return result; -} - -static CURLcode add_custom_headers(struct connectdata *conn, - send_buffer *req_buffer) -{ - CURLcode result = CURLE_OK; - char *ptr; - struct curl_slist *headers=conn->data->set.headers; - - while(headers) { - ptr = strchr(headers->data, ':'); - if(ptr) { - /* we require a colon for this to be a true header */ - - ptr++; /* pass the colon */ - while(*ptr && ISSPACE(*ptr)) - ptr++; - - if(*ptr) { - /* only send this if the contents was non-blank */ - - if(conn->allocptr.host && - /* a Host: header was sent already, don't pass on any custom Host: - header as that will produce *two* in the same request! */ - curl_strnequal("Host:", headers->data, 5)) - ; - else if(conn->data->set.httpreq == HTTPREQ_POST_FORM && - /* this header (extended by formdata.c) is sent later */ - curl_strnequal("Content-Type:", headers->data, - strlen("Content-Type:"))) - ; - else { - result = add_bufferf(req_buffer, "%s\r\n", headers->data); - if(result) - return result; - } - } - } - headers = headers->next; - } - return result; -} - -/* - * Curl_http() gets called from the generic Curl_do() function when a HTTP - * request is to be performed. This creates and sends a properly constructed - * HTTP request. - */ -CURLcode Curl_http(struct connectdata *conn, bool *done) -{ - struct SessionHandle *data=conn->data; - char *buf = data->state.buffer; /* this is a short cut to the buffer */ - CURLcode result=CURLE_OK; - struct HTTP *http; - char *ppath = data->reqdata.path; - char *host = conn->host.name; - const char *te = ""; /* transfer-encoding */ - char *ptr; - char *request; - Curl_HttpReq httpreq = data->set.httpreq; - char *addcookies = NULL; - curl_off_t included_body = 0; - - /* Always consider the DO phase done after this function call, even if there - 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; - - if(!data->reqdata.proto.http) { - /* Only allocate this struct if we don't already have it! */ - - http = (struct HTTP *)malloc(sizeof(struct HTTP)); - if(!http) - return CURLE_OUT_OF_MEMORY; - memset(http, 0, sizeof(struct HTTP)); - data->reqdata.proto.http = http; - } - else - http = data->reqdata.proto.http; - - /* We default to persistent connections */ - conn->bits.close = FALSE; - - if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) && - data->set.upload) { - httpreq = HTTPREQ_PUT; - } - - /* Now set the 'request' pointer to the proper request string */ - if(data->set.customrequest) - request = data->set.customrequest; - else { - if(conn->bits.no_body) - request = (char *)"HEAD"; - else { - curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST)); - switch(httpreq) { - case HTTPREQ_POST: - case HTTPREQ_POST_FORM: - request = (char *)"POST"; - break; - case HTTPREQ_PUT: - request = (char *)"PUT"; - break; - default: /* this should never happen */ - case HTTPREQ_GET: - request = (char *)"GET"; - break; - case HTTPREQ_HEAD: - request = (char *)"HEAD"; - break; - } - } - } - - /* The User-Agent string might have been allocated in url.c already, because - it might have been used in the proxy connect, but if we have got a header - with the user-agent string specified, we erase the previously made string - here. */ - if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) { - free(conn->allocptr.uagent); - conn->allocptr.uagent=NULL; - } - - /* setup the authentication headers */ - result = Curl_http_output_auth(conn, request, ppath, FALSE); - if(result) - return result; - - if((data->state.authhost.multi || data->state.authproxy.multi) && - (httpreq != HTTPREQ_GET) && - (httpreq != HTTPREQ_HEAD)) { - /* Auth is required and we are not authenticated yet. Make a PUT or POST - with content-length zero as a "probe". */ - conn->bits.authneg = TRUE; - } - else - conn->bits.authneg = FALSE; - - Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !checkheaders(data, "Referer:")) - conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); - else - conn->allocptr.ref = NULL; - - if(data->set.cookie && !checkheaders(data, "Cookie:")) - addcookies = data->set.cookie; - - if(!checkheaders(data, "Accept-Encoding:") && - data->set.encoding) { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.encoding); - if(!conn->allocptr.accept_encoding) - return CURLE_OUT_OF_MEMORY; - } - - ptr = checkheaders(data, "Transfer-Encoding:"); - if(ptr) { - /* Some kind of TE is requested, check if 'chunked' is chosen */ - conn->bits.upload_chunky = - Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); - } - else { - if (httpreq == HTTPREQ_GET) - conn->bits.upload_chunky = FALSE; - if(conn->bits.upload_chunky) - te = "Transfer-Encoding: chunked\r\n"; - } - - Curl_safefree(conn->allocptr.host); - - ptr = checkheaders(data, "Host:"); - if(ptr && (!data->state.this_is_a_follow || - curl_strequal(data->state.first_host, conn->host.name))) { -#if !defined(CURL_DISABLE_COOKIES) - /* 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 host name - is the same as the first one! */ - char *start = ptr+strlen("Host:"); - while(*start && ISSPACE(*start )) - start++; - ptr = start; /* start host-scanning here */ - - /* scan through the string to find the end (space or colon) */ - while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr)) - ptr++; - - if(ptr != start) { - size_t len=ptr-start; - Curl_safefree(conn->allocptr.cookiehost); - conn->allocptr.cookiehost = malloc(len+1); - if(!conn->allocptr.cookiehost) - return CURLE_OUT_OF_MEMORY; - memcpy(conn->allocptr.cookiehost, start, len); - conn->allocptr.cookiehost[len]=0; - } -#endif - - conn->allocptr.host = NULL; - } - else { - /* When building Host: headers, we must put the host name within - [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ - - if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) || - (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) ) - /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include - the port number in the host string */ - conn->allocptr.host = aprintf("Host: %s%s%s\r\n", - conn->bits.ipv6_ip?"[":"", - host, - conn->bits.ipv6_ip?"]":""); - else - conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n", - conn->bits.ipv6_ip?"[":"", - host, - conn->bits.ipv6_ip?"]":"", - conn->remote_port); - - if(!conn->allocptr.host) - /* without Host: we can't make a nice request */ - return CURLE_OUT_OF_MEMORY; - } - - if (conn->bits.httpproxy && !conn->bits.tunnel_proxy) { - /* Using a proxy but does not tunnel through it */ - - /* 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 host name! */ - if(conn->host.dispname != conn->host.name) { - char *url = data->change.url; - ptr = strstr(url, conn->host.dispname); - if(ptr) { - /* This is where the display name starts in the URL, now replace this - part with the encoded name. TODO: This method of replacing the host - name is rather crude as I believe there's a slight risk that the - user has entered a user name or password that contain the host name - string. */ - size_t currlen = strlen(conn->host.dispname); - size_t newlen = strlen(conn->host.name); - size_t urllen = strlen(url); - - char *newurl; - - newurl = malloc(urllen + newlen - currlen + 1); - if(newurl) { - /* copy the part before the host name */ - memcpy(newurl, url, ptr - url); - /* append the new host name instead of the old */ - memcpy(newurl + (ptr - url), conn->host.name, newlen); - /* append the piece after the host name */ - memcpy(newurl + newlen + (ptr - url), - ptr + currlen, /* copy the trailing zero byte too */ - urllen - (ptr-url) - currlen + 1); - if(data->change.url_alloc) - free(data->change.url); - data->change.url = newurl; - data->change.url_alloc = TRUE; - } - else - return CURLE_OUT_OF_MEMORY; - } - } - ppath = data->change.url; - } - if(HTTPREQ_POST_FORM == httpreq) { - /* we must build the whole darned post sequence first, so that we have - a size of the whole shebang before we start to send it */ - result = Curl_getFormData(&http->sendit, data->set.httppost, - checkheaders(data, "Content-Type:"), - &http->postsize); - if(CURLE_OK != result) { - /* Curl_getFormData() doesn't use failf() */ - failf(data, "failed creating formpost data"); - return result; - } - } - - - http->p_pragma = - (!checkheaders(data, "Pragma:") && - (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )? - "Pragma: no-cache\r\n":NULL; - - if(!checkheaders(data, "Accept:")) - http->p_accept = "Accept: */*\r\n"; - - if(( (HTTPREQ_POST == httpreq) || - (HTTPREQ_POST_FORM == httpreq) || - (HTTPREQ_PUT == httpreq) ) && - data->reqdata.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. - *********************************************************************/ - - if(data->reqdata.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->reqdata.resume_from = 0; - } - - if(data->reqdata.resume_from) { - /* do we still game? */ - curl_off_t passed=0; - - /* Now, let's read off the proper amount of bytes from the - input. If we knew it was a proper file we could've just - fseek()ed but we only have a stream here */ - do { - size_t readthisamountnow = (size_t)(data->reqdata.resume_from - passed); - size_t actuallyread; - - if(readthisamountnow > BUFSIZE) - readthisamountnow = BUFSIZE; - - actuallyread = - data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow, - data->set.in); - - passed += actuallyread; - if(actuallyread != readthisamountnow) { - failf(data, "Could only read %" FORMAT_OFF_T - " bytes from the input", - passed); - return CURLE_READ_ERROR; - } - } while(passed != data->reqdata.resume_from); /* loop until done */ - - /* now, decrease the size of the read */ - if(data->set.infilesize>0) { - data->set.infilesize -= data->reqdata.resume_from; - - if(data->set.infilesize <= 0) { - failf(data, "File already completely uploaded"); - return CURLE_PARTIAL_FILE; - } - } - /* we've passed, proceed as normal */ - } - } - if(data->reqdata.use_range) { - /* - * 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. - */ - if((httpreq == HTTPREQ_GET) && - !checkheaders(data, "Range:")) { - /* if a line like this was already allocated, free the previous one */ - if(conn->allocptr.rangeline) - free(conn->allocptr.rangeline); - conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->reqdata.range); - } - else if((httpreq != HTTPREQ_GET) && - !checkheaders(data, "Content-Range:")) { - - if(data->reqdata.resume_from) { - /* This is because "resume" was selected */ - curl_off_t total_expected_size= - data->reqdata.resume_from + data->set.infilesize; - conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s%" FORMAT_OFF_T - "/%" FORMAT_OFF_T "\r\n", - data->reqdata.range, total_expected_size-1, - total_expected_size); - } - else { - /* Range was selected and then we just pass the incoming range and - append total size */ - conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", - data->reqdata.range, data->set.infilesize); - } - } - } - - { - /* Use 1.1 unless the use specificly asked for 1.0 */ - const char *httpstring= - data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1"; - - send_buffer *req_buffer; - curl_off_t postsize; /* off_t type to be able to hold a large file size */ - - /* initialize a dynamic send-buffer */ - req_buffer = add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - - /* add the main request stuff */ - result = - add_bufferf(req_buffer, - "%s " /* GET/HEAD/POST/PUT */ - "%s HTTP/%s\r\n" /* path + HTTP version */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* host */ - "%s" /* pragma */ - "%s" /* accept */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s",/* transfer-encoding */ - - request, - ppath, - httpstring, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->reqdata.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)? - conn->allocptr.uagent:"", - (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ - http->p_pragma?http->p_pragma:"", - http->p_accept?http->p_accept:"", - (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !checkheaders(data, "Proxy-Connection:"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te - ); - - if(result) - return result; - -#if !defined(CURL_DISABLE_COOKIES) - if(data->cookies || addcookies) { - struct Cookie *co=NULL; /* no cookies from start */ - int count=0; - - if(data->cookies) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - co = Curl_cookie_getlist(data->cookies, - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:host, data->reqdata.path, - (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE)); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - if(co) { - struct Cookie *store=co; - /* now loop through all cookies that matched */ - while(co) { - if(co->value) { - if(0 == count) { - result = add_bufferf(req_buffer, "Cookie: "); - if(result) - break; - } - result = add_bufferf(req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); - if(result) - break; - count++; - } - co = co->next; /* next cookie please */ - } - Curl_cookie_freelist(store); /* free the cookie list */ - } - if(addcookies && (CURLE_OK == result)) { - if(!count) - result = add_bufferf(req_buffer, "Cookie: "); - if(CURLE_OK == result) { - result = add_bufferf(req_buffer, "%s%s", - count?"; ":"", - addcookies); - count++; - } - } - if(count && (CURLE_OK == result)) - result = add_buffer(req_buffer, "\r\n", 2); - - if(result) - return result; - } -#endif - - if(data->set.timecondition) { - struct tm *tm; - - /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since - * header family should have their times set in GMT as RFC2616 defines: - * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time - * (GMT), without exception. For the purposes of HTTP, GMT is exactly - * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616). - */ - -#ifdef HAVE_GMTIME_R - /* thread-safe version */ - struct tm keeptime; - tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime); -#else - tm = gmtime(&data->set.timevalue); -#endif - - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(buf, BUFSIZE-1, - "%s, %02d %s %4d %02d:%02d:%02d GMT", - 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); - - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - result = add_bufferf(req_buffer, - "If-Modified-Since: %s\r\n", buf); - break; - case CURL_TIMECOND_IFUNMODSINCE: - result = add_bufferf(req_buffer, - "If-Unmodified-Since: %s\r\n", buf); - break; - case CURL_TIMECOND_LASTMOD: - result = add_bufferf(req_buffer, - "Last-Modified: %s\r\n", buf); - break; - } - if(result) - return result; - } - - result = add_custom_headers(conn, req_buffer); - if(result) - return result; - - http->postdata = NULL; /* nothing to post at this point */ - Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */ - - /* If 'authdone' is FALSE, we must not set the write socket index to the - Curl_transfer() call below, as we're not ready to actually upload any - data yet. */ - - switch(httpreq) { - - case HTTPREQ_POST_FORM: - if(!http->sendit || conn->bits.authneg) { - /* nothing to post! */ - result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n"); - if(result) - return result; - - result = add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending POST request"); - else - /* setup variables for the upcoming transfer */ - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, - -1, NULL); - break; - } - - if(Curl_FormInit(&http->form, http->sendit)) { - failf(data, "Internal HTTP POST error!"); - return CURLE_HTTP_POST_ERROR; - } - - /* set the read function to read from the generated form data */ - conn->fread = (curl_read_callback)Curl_FormReader; - conn->fread_in = &http->form; - - http->sending = HTTPSEND_BODY; - - if(!conn->bits.upload_chunky) { - /* only add Content-Length if not uploading chunked */ - result = add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - http->postsize); - if(result) - return result; - } - - result = expect100(data, req_buffer); - if(result) - return result; - - { - - /* Get Content-Type: line from Curl_formpostheader. - */ - char *contentType; - size_t linelength=0; - contentType = Curl_formpostheader((void *)&http->form, - &linelength); - if(!contentType) { - failf(data, "Could not get Content-Type header line!"); - return CURLE_HTTP_POST_ERROR; - } - - result = add_buffer(req_buffer, contentType, linelength); - if(result) - return result; - } - - /* make the request end in a true CRLF */ - result = add_buffer(req_buffer, "\r\n", 2); - if(result) - return result; - - /* set upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, http->postsize); - - /* fire away the whole request to the server */ - result = add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending POST request"); - else - /* setup variables for the upcoming transfer */ - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, - FIRSTSOCKET, - &http->writebytecount); - - if(result) { - Curl_formclean(&http->sendit); /* free that whole lot */ - return result; - } -#ifdef CURL_DOES_CONVERSIONS -/* time to convert the form data... */ - result = Curl_formconvert(data, http->sendit); - if(result) { - Curl_formclean(&http->sendit); /* free that whole lot */ - return result; - } -#endif /* CURL_DOES_CONVERSIONS */ - break; - - case HTTPREQ_PUT: /* Let's PUT the data to the server! */ - - if(conn->bits.authneg) - postsize = 0; - else - postsize = data->set.infilesize; - - if((postsize != -1) && !conn->bits.upload_chunky) { - /* only add Content-Length if not uploading chunked */ - result = add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - postsize ); - if(result) - return result; - } - - result = expect100(data, req_buffer); - if(result) - return result; - - result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */ - if(result) - return result; - - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, postsize); - - /* this sends the buffer and frees all the buffer resources */ - result = add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending PUT request"); - else - /* prepare for transfer */ - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, - postsize?FIRSTSOCKET:-1, - postsize?&http->writebytecount:NULL); - if(result) - return result; - break; - - case HTTPREQ_POST: - /* this is the simple POST, using x-www-form-urlencoded style */ - - if(conn->bits.authneg) - postsize = 0; - else - /* figure out the size of the postfields */ - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: - (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0); - - if(!conn->bits.upload_chunky) { - /* 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(!checkheaders(data, "Content-Length:")) { - /* we allow replacing this header, although it isn't very wise to - actually set your own */ - result = add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T"\r\n", - postsize); - if(result) - return result; - } - } - - if(!checkheaders(data, "Content-Type:")) { - result = add_bufferf(req_buffer, - "Content-Type: application/x-www-form-urlencoded\r\n"); - if(result) - return result; - } - - if(data->set.postfields) { - - /* for really small posts we don't use Expect: headers at all, and for - the somewhat bigger ones we allow the app to disable it */ - if(postsize > TINY_INITIAL_POST_SIZE) { - result = expect100(data, req_buffer); - if(result) - return result; - } - else - data->state.expect100header = FALSE; - - if(!data->state.expect100header && - (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. */ - - result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ - if(result) - return result; - - if(!conn->bits.upload_chunky) { - /* We're not sending it 'chunked', append it to the request - already now to reduce the number if send() calls */ - result = add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); - included_body = postsize; - } - else { - /* Append the POST data chunky-style */ - result = add_bufferf(req_buffer, "%x\r\n", (int)postsize); - if(CURLE_OK == result) - result = add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); - if(CURLE_OK == result) - result = add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); - /* CR LF 0 CR LF CR LF */ - included_body = postsize + 7; - } - if(result) - return result; - } - else { - /* A huge POST coming up, do data separate from the request */ - http->postsize = postsize; - http->postdata = data->set.postfields; - - http->sending = HTTPSEND_BODY; - - conn->fread = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; - - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, http->postsize); - - add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ - } - } - else { - add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ - - if(data->set.postfieldsize) { - /* set the upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, postsize?postsize:-1); - - /* set the pointer to mark that we will send the post body using - the read callback */ - http->postdata = (char *)&http->postdata; - } - } - /* issue the request */ - result = add_buffer_send(req_buffer, conn, &data->info.request_size, - (size_t)included_body, FIRSTSOCKET); - - if(result) - failf(data, "Failed sending HTTP POST request"); - else - result = - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, - http->postdata?FIRSTSOCKET:-1, - http->postdata?&http->writebytecount:NULL); - break; - - default: - add_buffer(req_buffer, "\r\n", 2); - - /* issue the request */ - result = add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - - if(result) - failf(data, "Failed sending HTTP request"); - else - /* HTTP GET/HEAD download: */ - result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, - http->postdata?FIRSTSOCKET:-1, - http->postdata?&http->writebytecount:NULL); - } - if(result) - return result; - } - - return CURLE_OK; -} -#endif diff --git a/Utilities/cmcurl/http.h b/Utilities/cmcurl/http.h deleted file mode 100644 index 0f4b58f..0000000 --- a/Utilities/cmcurl/http.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __HTTP_H -#define __HTTP_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_HTTP -bool Curl_compareheader(char *headerline, /* line to check */ - const char *header, /* header keyword _with_ colon */ - const char *content); /* content string to find */ - -/* ftp can use this as well */ -CURLcode Curl_proxyCONNECT(struct connectdata *conn, - int tunnelsocket, - char *hostname, int remote_port); - -/* protocol-specific functions set up to be called by the main engine */ -CURLcode Curl_http(struct connectdata *conn, bool *done); -CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); -CURLcode Curl_http_connect(struct connectdata *conn, bool *done); -CURLcode Curl_https_connecting(struct connectdata *conn, bool *done); -int Curl_https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - -/* The following functions are defined in http_chunks.c */ -void Curl_httpchunk_init(struct connectdata *conn); -CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, - ssize_t length, ssize_t *wrote); - -/* These functions are in http.c */ -void Curl_http_auth_stage(struct SessionHandle *data, int stage); -CURLcode Curl_http_input_auth(struct connectdata *conn, - int httpcode, char *header); -CURLcode Curl_http_auth_act(struct connectdata *conn); - -int Curl_http_should_fail(struct connectdata *conn); - -/* If only the PICKNONE bit is set, there has been a round-trip and we - 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) /* 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 - data is larger than this, it will automatically get split up in multiple - system calls. - - This value used to be fairly big (100K), but we must take into account that - if the server rejects the POST due for authentication reasons, this data - will always be uncondtionally sent and thus it may not be larger than can - always be afforded to send twice. - - It must not be greater than 64K to work on VMS. -*/ -#ifndef MAX_INITIAL_POST_SIZE -#define MAX_INITIAL_POST_SIZE (64*1024) -#endif - -#ifndef TINY_INITIAL_POST_SIZE -#define TINY_INITIAL_POST_SIZE 1024 -#endif - -#endif -#endif diff --git a/Utilities/cmcurl/http_chunks.c b/Utilities/cmcurl/http_chunks.c deleted file mode 100644 index 1b03a55..0000000 --- a/Utilities/cmcurl/http_chunks.c +++ /dev/null @@ -1,360 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#include "setup.h" - -#ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#include "urldata.h" /* it includes http_chunks.h */ -#include "sendf.h" /* for the client write stuff */ - -#include "content_encoding.h" -#include "http.h" -#include "memory.h" -#include "easyif.h" /* for Curl_convert_to_network prototype */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Chunk format (simplified): - * - * [ chunk extension ] CRLF - * CRLF - * - * Highlights from RFC2616 section 3.6 say: - - The chunked encoding modifies the body of a message in order to - transfer it as a series of chunks, each with its own size indicator, - followed by an OPTIONAL trailer containing entity-header fields. This - allows dynamically produced content to be transferred along with the - information necessary for the recipient to verify that it has - received the full message. - - Chunked-Body = *chunk - last-chunk - trailer - CRLF - - chunk = chunk-size [ chunk-extension ] CRLF - chunk-data CRLF - chunk-size = 1*HEX - last-chunk = 1*("0") [ chunk-extension ] CRLF - - chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) - chunk-ext-name = token - chunk-ext-val = token | quoted-string - chunk-data = chunk-size(OCTET) - trailer = *(entity-header CRLF) - - The chunk-size field is a string of hex digits indicating the size of - the chunk. The chunked encoding is ended by any chunk whose size is - zero, followed by the trailer, which is terminated by an empty line. - - */ - - -void Curl_httpchunk_init(struct connectdata *conn) -{ - struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk; - chunk->hexindex=0; /* start at 0 */ - chunk->dataleft=0; /* no data left yet! */ - chunk->state = CHUNK_HEX; /* we get hex first! */ -} - -/* - * 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 connectdata *conn, - char *datap, - ssize_t datalen, - ssize_t *wrotep) -{ - CURLcode result=CURLE_OK; - struct SessionHandle *data = conn->data; - struct Curl_chunker *ch = &data->reqdata.proto.http->chunk; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - size_t piece; - size_t length = (size_t)datalen; - size_t *wrote = (size_t *)wrotep; - - *wrote = 0; /* nothing's written yet */ - - while(length) { - switch(ch->state) { - case CHUNK_HEX: - /* Check for an ASCII hex digit. - We avoid the use of isxdigit to accommodate non-ASCII hosts. */ - if((*datap >= 0x30 && *datap <= 0x39) /* 0-9 */ - || (*datap >= 0x41 && *datap <= 0x46) /* A-F */ - || (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */ - if(ch->hexindex < MAXNUM_SIZE) { - ch->hexbuffer[ch->hexindex] = *datap; - datap++; - length--; - ch->hexindex++; - } - else { - return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ - } - } - else { - if(0 == ch->hexindex) { - /* This is illegal data, we received junk where we expected - a hexadecimal digit. */ - return CHUNKE_ILLEGAL_HEX; - } - /* length and datap are unmodified */ - ch->hexbuffer[ch->hexindex]=0; -#ifdef CURL_DOES_CONVERSIONS - /* convert to host encoding before calling strtoul */ - result = Curl_convert_from_network(conn->data, - ch->hexbuffer, - ch->hexindex); - if(result != CURLE_OK) { - /* Curl_convert_from_network calls failf if unsuccessful */ - /* Treat it as a bad hex character */ - return(CHUNKE_ILLEGAL_HEX); - } -#endif /* CURL_DOES_CONVERSIONS */ - ch->datasize=strtoul(ch->hexbuffer, NULL, 16); - ch->state = CHUNK_POSTHEX; - } - break; - - case CHUNK_POSTHEX: - /* In this state, we're waiting for CRLF to arrive. We support - this to allow so called chunk-extensions to show up here - before the CRLF comes. */ - if(*datap == 0x0d) - ch->state = CHUNK_CR; - length--; - datap++; - break; - - case CHUNK_CR: - /* waiting for the LF */ - if(*datap == 0x0a) { - /* we're now expecting data to come, unless size was zero! */ - if(0 == ch->datasize) { - if (conn->bits.trailerHdrPresent!=TRUE) { - /* No Trailer: header found - revert to original Curl processing */ - ch->state = CHUNK_STOP; - if (1 == length) { - /* This is the final byte, return right now */ - return CHUNKE_STOP; - } - } - else { - ch->state = CHUNK_TRAILER; /* attempt to read trailers */ - conn->trlPos=0; - } - } - else - ch->state = CHUNK_DATA; - } - else - /* previously we got a fake CR, go back to CR waiting! */ - ch->state = CHUNK_CR; - datap++; - length--; - break; - - case CHUNK_DATA: - /* we get pure and fine data - - We expect another 'datasize' of data. We have 'length' right now, - it can be more or less than 'datasize'. Get the smallest piece. - */ - piece = (ch->datasize >= length)?length:ch->datasize; - - /* Write the data portion available */ -#ifdef HAVE_LIBZ - switch (data->reqdata.keep.content_encoding) { - case IDENTITY: -#endif - if(!k->ignorebody) - result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, - piece); -#ifdef HAVE_LIBZ - break; - - case DEFLATE: - /* update data->reqdata.keep.str to point to the chunk data. */ - data->reqdata.keep.str = datap; - result = Curl_unencode_deflate_write(conn, &data->reqdata.keep, - (ssize_t)piece); - break; - - case GZIP: - /* update data->reqdata.keep.str to point to the chunk data. */ - data->reqdata.keep.str = datap; - result = Curl_unencode_gzip_write(conn, &data->reqdata.keep, - (ssize_t)piece); - break; - - case COMPRESS: - default: - failf (conn->data, - "Unrecognized content encoding type. " - "libcurl understands `identity', `deflate' and `gzip' " - "content encodings."); - return CHUNKE_BAD_ENCODING; - } -#endif - - if(result) - return CHUNKE_WRITE_ERROR; - - *wrote += piece; - - ch->datasize -= piece; /* decrease amount left to expect */ - datap += piece; /* move read pointer forward */ - length -= piece; /* decrease space left in this round */ - - if(0 == ch->datasize) - /* end of data this round, we now expect a trailing CRLF */ - ch->state = CHUNK_POSTCR; - break; - - case CHUNK_POSTCR: - if(*datap == 0x0d) { - ch->state = CHUNK_POSTLF; - datap++; - length--; - } - else - return CHUNKE_BAD_CHUNK; - break; - - case CHUNK_POSTLF: - if(*datap == 0x0a) { - /* - * The last one before we go back to hex state and start all - * over. - */ - Curl_httpchunk_init(conn); - datap++; - length--; - } - else - return CHUNKE_BAD_CHUNK; - break; - - case CHUNK_TRAILER: - /* conn->trailer is assumed to be freed in url.c on a - connection basis */ - if (conn->trlPos >= conn->trlMax) { - char *ptr; - if(conn->trlMax) { - conn->trlMax *= 2; - ptr = (char*)realloc(conn->trailer,conn->trlMax); - } - else { - conn->trlMax=128; - ptr = (char*)malloc(conn->trlMax); - } - if(!ptr) - return CHUNKE_OUT_OF_MEMORY; - conn->trailer = ptr; - } - conn->trailer[conn->trlPos++]=*datap; - - if(*datap == 0x0d) - ch->state = CHUNK_TRAILER_CR; - else { - datap++; - length--; - } - break; - - case CHUNK_TRAILER_CR: - if(*datap == 0x0d) { - ch->state = CHUNK_TRAILER_POSTCR; - datap++; - length--; - } - else - return CHUNKE_BAD_CHUNK; - break; - - case CHUNK_TRAILER_POSTCR: - if (*datap == 0x0a) { - conn->trailer[conn->trlPos++]=0x0a; - conn->trailer[conn->trlPos]=0; - if (conn->trlPos==2) { - ch->state = CHUNK_STOP; - return CHUNKE_STOP; - } - else { -#ifdef CURL_DOES_CONVERSIONS - /* Convert to host encoding before calling Curl_client_write */ - result = Curl_convert_from_network(conn->data, - conn->trailer, - conn->trlPos); - if(result != CURLE_OK) { - /* Curl_convert_from_network calls failf if unsuccessful */ - /* Treat it as a bad chunk */ - return(CHUNKE_BAD_CHUNK); - } -#endif /* CURL_DOES_CONVERSIONS */ - Curl_client_write(conn, CLIENTWRITE_HEADER, - conn->trailer, conn->trlPos); - } - ch->state = CHUNK_TRAILER; - conn->trlPos=0; - datap++; - length--; - } - else - return CHUNKE_BAD_CHUNK; - break; - - case CHUNK_STOP: - /* If we arrive here, there is data left in the end of the buffer - even if there's no more chunks to read */ - ch->dataleft = length; - return CHUNKE_STOP; /* return stop */ - default: - return CHUNKE_STATE_ERROR; - } - } - return CHUNKE_OK; -} -#endif /* CURL_DISABLE_HTTP */ diff --git a/Utilities/cmcurl/http_chunks.h b/Utilities/cmcurl/http_chunks.h deleted file mode 100644 index 211818a..0000000 --- a/Utilities/cmcurl/http_chunks.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __HTTP_CHUNKS_H -#define __HTTP_CHUNKS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -/* - * The longest possible hexadecimal number we support in a chunked transfer. - * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul() - * to convert it, we "only" support 2^32 bytes chunk data. - */ -#define MAXNUM_SIZE 16 - -typedef enum { - CHUNK_FIRST, /* never use */ - - /* In this we await and buffer all hexadecimal digits until we get one - that isn't a hexadecimal digit. When done, we go POSTHEX */ - CHUNK_HEX, - - /* We have received the hexadecimal digit and we eat all characters until - we get a CRLF pair. When we see a CR we go to the CR state. */ - CHUNK_POSTHEX, - - /* A single CR has been found and we should get a LF right away in this - state or we go back to POSTHEX. When LF is received, we go to DATA. - If the size given was zero, we set state to STOP and return. */ - CHUNK_CR, - - /* We eat the amount of data specified. When done, we move on to the - POST_CR state. */ - CHUNK_DATA, - - /* POSTCR should get a CR and nothing else, then move to POSTLF */ - CHUNK_POSTCR, - - /* POSTLF should get a LF and nothing else, then move back to HEX as the - CRLF combination marks the end of a chunk */ - CHUNK_POSTLF, - - /* This is mainly used to really mark that we're out of the game. - NOTE: that there's a 'dataleft' 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 - is CRLF */ - CHUNK_TRAILER, - - /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. - Next char must be a LF */ - CHUNK_TRAILER_CR, - - /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be - 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, - - CHUNK_LAST /* never use */ - -} ChunkyState; - -typedef enum { - CHUNKE_STOP = -1, - CHUNKE_OK = 0, - CHUNKE_TOO_LONG_HEX = 1, - CHUNKE_ILLEGAL_HEX, - CHUNKE_BAD_CHUNK, - CHUNKE_WRITE_ERROR, - CHUNKE_STATE_ERROR, - CHUNKE_BAD_ENCODING, - CHUNKE_OUT_OF_MEMORY, - CHUNKE_LAST -} CHUNKcode; - -struct Curl_chunker { - char hexbuffer[ MAXNUM_SIZE + 1]; - int hexindex; - ChunkyState state; - size_t datasize; - size_t dataleft; /* untouched data amount at the end of the last buffer */ -}; - -#endif diff --git a/Utilities/cmcurl/http_digest.c b/Utilities/cmcurl/http_digest.c deleted file mode 100644 index c223784..0000000 --- a/Utilities/cmcurl/http_digest.c +++ /dev/null @@ -1,504 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#include "setup.h" - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#include "urldata.h" -#include "sendf.h" -#include "strequal.h" -#include "base64.h" -#include "md5.h" -#include "http_digest.h" -#include "strtok.h" -#include "url.h" /* for Curl_safefree() */ -#include "memory.h" -#include "easyif.h" /* included for Curl_convert_... prototypes */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -/* Test example headers: - -WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" -Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" - -*/ - -CURLdigest Curl_input_digest(struct connectdata *conn, - bool proxy, - char *header) /* rest of the *-authenticate: - header */ -{ - bool more = TRUE; - char *token = NULL; - char *tmp = NULL; - bool foundAuth = FALSE; - bool foundAuthInt = FALSE; - struct SessionHandle *data=conn->data; - bool before = FALSE; /* got a nonce before */ - struct digestdata *d; - - if(proxy) { - d = &data->state.proxydigest; - } - else { - d = &data->state.digest; - } - - /* skip initial whitespaces */ - while(*header && ISSPACE(*header)) - header++; - - if(checkprefix("Digest", header)) { - header += strlen("Digest"); - - /* If we already have received a nonce, keep that in mind */ - if(d->nonce) - before = TRUE; - - /* clear off any former leftovers and init to defaults */ - Curl_digest_cleanup_one(d); - - while(more) { - char value[32]; - char content[128]; - size_t totlen=0; - - while(*header && ISSPACE(*header)) - header++; - - /* how big can these strings be? */ - if((2 == sscanf(header, "%31[^=]=\"%127[^\"]\"", - value, content)) || - /* try the same scan but without quotes around the content but don't - include the possibly trailing comma */ - (2 == sscanf(header, "%31[^=]=%127[^,]", - value, content)) ) { - if(strequal(value, "nonce")) { - d->nonce = strdup(content); - if(!d->nonce) - return CURLDIGEST_NOMEM; - } - else if(strequal(value, "stale")) { - if(strequal(content, "true")) { - d->stale = TRUE; - d->nc = 1; /* we make a new nonce now */ - } - } - else if(strequal(value, "realm")) { - d->realm = strdup(content); - if(!d->realm) - return CURLDIGEST_NOMEM; - } - else if(strequal(value, "opaque")) { - d->opaque = strdup(content); - if(!d->opaque) - return CURLDIGEST_NOMEM; - } - else if(strequal(value, "qop")) { - char *tok_buf; - /* tokenize the list and choose auth if possible, use a temporary - clone of the buffer since strtok_r() ruins it */ - tmp = strdup(content); - if(!tmp) - return CURLDIGEST_NOMEM; - token = strtok_r(tmp, ",", &tok_buf); - while (token != NULL) { - if (strequal(token, "auth")) { - foundAuth = TRUE; - } - else if (strequal(token, "auth-int")) { - foundAuthInt = TRUE; - } - token = strtok_r(NULL, ",", &tok_buf); - } - free(tmp); - /*select only auth o auth-int. Otherwise, ignore*/ - if (foundAuth) { - d->qop = strdup("auth"); - if(!d->qop) - return CURLDIGEST_NOMEM; - } - else if (foundAuthInt) { - d->qop = strdup("auth-int"); - if(!d->qop) - return CURLDIGEST_NOMEM; - } - } - else if(strequal(value, "algorithm")) { - d->algorithm = strdup(content); - if(!d->algorithm) - return CURLDIGEST_NOMEM; - if(strequal(content, "MD5-sess")) - d->algo = CURLDIGESTALGO_MD5SESS; - else if(strequal(content, "MD5")) - d->algo = CURLDIGESTALGO_MD5; - else - return CURLDIGEST_BADALGO; - } - else { - /* unknown specifier, ignore it! */ - } - totlen = strlen(value)+strlen(content)+1; - - if(header[strlen(value)+1] == '\"') - /* the contents were within quotes, then add 2 for them to the - length */ - totlen += 2; - } - else - break; /* we're done here */ - - header += totlen; - if(',' == *header) - /* allow the list to be comma-separated */ - header++; - } - /* We had a nonce since before, and we got another one now without - 'stale=true'. This means we provided bad credentials in the previous - request */ - if(before && !d->stale) - return CURLDIGEST_BAD; - - /* We got this header without a nonce, that's a bad Digest line! */ - if(!d->nonce) - return CURLDIGEST_BAD; - } - else - /* else not a digest, get out */ - return CURLDIGEST_NONE; - - return CURLDIGEST_FINE; -} - -/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ -static void md5_to_ascii(unsigned char *source, /* 16 bytes */ - unsigned char *dest) /* 33 bytes */ -{ - int i; - for(i=0; i<16; i++) - snprintf((char *)&dest[i*2], 3, "%02x", source[i]); -} - -CURLcode Curl_output_digest(struct connectdata *conn, - bool proxy, - unsigned char *request, - unsigned char *uripath) -{ - /* We have a Digest setup for this, use it! Now, to get all the details for - this sorted out, I must urge you dear friend to read up on the RFC2617 - section 3.2.2, */ - unsigned char md5buf[16]; /* 16 bytes/128 bits */ - unsigned char request_digest[33]; - unsigned char *md5this; - unsigned char *ha1; - unsigned char ha2[33];/* 32 digits and 1 zero byte */ - char cnoncebuf[7]; - char *cnonce; - char *tmp = NULL; - struct timeval now; - - char **allocuserpwd; - char *userp; - char *passwdp; - struct auth *authp; - - struct SessionHandle *data = conn->data; - struct digestdata *d; -#ifdef CURL_DOES_CONVERSIONS - CURLcode rc; -/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. - It converts digest text to ASCII so the MD5 will be correct for - what ultimately goes over the network. -*/ -#define CURL_OUTPUT_DIGEST_CONV(a, b) \ - rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ - if (rc != CURLE_OK) { \ - free(b); \ - return rc; \ - } -#else -#define CURL_OUTPUT_DIGEST_CONV(a, b) -#endif /* CURL_DOES_CONVERSIONS */ - - if(proxy) { - d = &data->state.proxydigest; - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - authp = &data->state.authproxy; - } - else { - d = &data->state.digest; - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - authp = &data->state.authhost; - } - - /* not set means empty */ - if(!userp) - userp=(char *)""; - - if(!passwdp) - passwdp=(char *)""; - - if(!d->nonce) { - authp->done = FALSE; - return CURLE_OK; - } - authp->done = TRUE; - - if(!d->nc) - d->nc = 1; - - if(!d->cnonce) { - /* Generate a cnonce */ - now = Curl_tvnow(); - snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec); - if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce)) - d->cnonce = cnonce; - else - return CURLE_OUT_OF_MEMORY; - } - - /* - if the algorithm is "MD5" or unspecified (which then defaults to MD5): - - A1 = unq(username-value) ":" unq(realm-value) ":" passwd - - if the algorithm is "MD5-sess" then: - - A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) - ":" unq(nonce-value) ":" unq(cnonce-value) - */ - - md5this = (unsigned char *) - aprintf("%s:%s:%s", userp, d->realm, passwdp); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); /* free this again */ - - ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */ - if(!ha1) - return CURLE_OUT_OF_MEMORY; - - md5_to_ascii(md5buf, ha1); - - if(d->algo == CURLDIGESTALGO_MD5SESS) { - /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, (unsigned char *)tmp); - free(tmp); /* free this again */ - md5_to_ascii(md5buf, ha1); - } - - /* - If the "qop" directive's value is "auth" or is unspecified, then A2 is: - - A2 = Method ":" digest-uri-value - - If the "qop" value is "auth-int", then A2 is: - - A2 = Method ":" digest-uri-value ":" H(entity-body) - - (The "Method" value is the HTTP request method as specified in section - 5.1.1 of RFC 2616) - */ - - md5this = (unsigned char *)aprintf("%s:%s", request, uripath); - if(!md5this) { - free(ha1); - return CURLE_OUT_OF_MEMORY; - } - - if (d->qop && strequal(d->qop, "auth-int")) { - /* We don't support auth-int at the moment. I can't see a easy way to get - entity-body here */ - /* TODO: Append H(entity-body)*/ - } - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); /* free this again */ - md5_to_ascii(md5buf, ha2); - - if (d->qop) { - md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - d->nonce, - d->nc, - d->cnonce, - d->qop, - ha2); - } - else { - md5this = (unsigned char *)aprintf("%s:%s:%s", - ha1, - d->nonce, - ha2); - } - free(ha1); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); /* free this again */ - md5_to_ascii(md5buf, request_digest); - - /* for test case 64 (snooped from a Mozilla 1.3a request) - - Authorization: Digest username="testuser", realm="testrealm", \ - nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" - */ - - Curl_safefree(*allocuserpwd); - - if (d->qop) { - *allocuserpwd = - aprintf( "%sAuthorization: Digest " - "username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=\"%s\", " - "response=\"%s\"", - proxy?"Proxy-":"", - userp, - d->realm, - d->nonce, - uripath, /* this is the PATH part of the URL */ - d->cnonce, - d->nc, - d->qop, - request_digest); - - if(strequal(d->qop, "auth")) - d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded - which tells to the server how many times you are using the - same nonce in the qop=auth mode. */ - } - else { - *allocuserpwd = - aprintf( "%sAuthorization: Digest " - "username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "response=\"%s\"", - proxy?"Proxy-":"", - userp, - d->realm, - d->nonce, - uripath, /* this is the PATH part of the URL */ - request_digest); - } - if(!*allocuserpwd) - return CURLE_OUT_OF_MEMORY; - - /* Add optional fields */ - if(d->opaque) { - /* append opaque */ - tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - free(*allocuserpwd); - *allocuserpwd = tmp; - } - - if(d->algorithm) { - /* append algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - free(*allocuserpwd); - *allocuserpwd = tmp; - } - - /* append CRLF to the userpwd header */ - tmp = (char*) realloc(*allocuserpwd, strlen(*allocuserpwd) + 3 + 1); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - strcat(tmp, "\r\n"); - *allocuserpwd = tmp; - - return CURLE_OK; -} - -void Curl_digest_cleanup_one(struct digestdata *d) -{ - if(d->nonce) - free(d->nonce); - d->nonce = NULL; - - if(d->cnonce) - free(d->cnonce); - d->cnonce = NULL; - - if(d->realm) - free(d->realm); - d->realm = NULL; - - if(d->opaque) - free(d->opaque); - d->opaque = NULL; - - if(d->qop) - free(d->qop); - d->qop = NULL; - - if(d->algorithm) - free(d->algorithm); - d->algorithm = NULL; - - d->nc = 0; - d->algo = CURLDIGESTALGO_MD5; /* default algorithm */ - d->stale = FALSE; /* default means normal, not stale */ -} - - -void Curl_digest_cleanup(struct SessionHandle *data) -{ - Curl_digest_cleanup_one(&data->state.digest); - Curl_digest_cleanup_one(&data->state.proxydigest); -} - -#endif diff --git a/Utilities/cmcurl/http_digest.h b/Utilities/cmcurl/http_digest.h deleted file mode 100644 index 6cf0259..0000000 --- a/Utilities/cmcurl/http_digest.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __HTTP_DIGEST_H -#define __HTTP_DIGEST_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -typedef enum { - CURLDIGEST_NONE, /* not a digest */ - CURLDIGEST_BAD, /* a digest, but one we don't like */ - CURLDIGEST_BADALGO, /* unsupported algorithm requested */ - CURLDIGEST_NOMEM, - CURLDIGEST_FINE, /* a digest we act on */ - - CURLDIGEST_LAST /* last entry in this enum, don't use */ -} CURLdigest; - -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS -}; - -/* this is for digest header input */ -CURLdigest Curl_input_digest(struct connectdata *conn, - bool proxy, char *header); - -/* this is for creating digest header output */ -CURLcode Curl_output_digest(struct connectdata *conn, - bool proxy, - unsigned char *request, - unsigned char *uripath); -void Curl_digest_cleanup_one(struct digestdata *dig); - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -void Curl_digest_cleanup(struct SessionHandle *data); -#else -#define Curl_digest_cleanup(x) do {} while(0) -#endif - -#endif diff --git a/Utilities/cmcurl/http_negotiate.c b/Utilities/cmcurl/http_negotiate.c deleted file mode 100644 index bdfeefa..0000000 --- a/Utilities/cmcurl/http_negotiate.c +++ /dev/null @@ -1,327 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#include "setup.h" - -#ifdef HAVE_GSSAPI -#ifdef HAVE_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif - -#ifndef CURL_DISABLE_HTTP - /* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#include "urldata.h" -#include "sendf.h" -#include "strequal.h" -#include "base64.h" -#include "http_negotiate.h" -#include "memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -static int -get_gss_name(struct connectdata *conn, gss_name_t *server) -{ - struct negotiatedata *neg_ctx = &conn->data->state.negotiate; - OM_uint32 major_status, minor_status; - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - char name[2048]; - const char* service; - - /* GSSAPI implementation by Globus (known as GSI) requires the name to be - of form "/" instead of @ (ie. slash instead - of at-sign). Also GSI servers are often identified as 'host' not 'khttp'. - Change following lines if you want to use GSI */ - - /* IIS uses the @ form but uses 'http' as the service name */ - - if (neg_ctx->gss) - service = "KHTTP"; - else - service = "HTTP"; - - token.length = strlen(service) + 1 + strlen(conn->host.name) + 1; - if (token.length + 1 > sizeof(name)) - return EMSGSIZE; - - snprintf(name, sizeof(name), "%s@%s", service, conn->host.name); - - token.value = (void *) name; - major_status = gss_import_name(&minor_status, - &token, - GSS_C_NT_HOSTBASED_SERVICE, - server); - - return GSS_ERROR(major_status) ? -1 : 0; -} - -static void -log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix) -{ - OM_uint32 maj_stat, min_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - char buf[1024]; - size_t len; - - snprintf(buf, sizeof(buf), "%s", prefix); - len = strlen(buf); - do { - maj_stat = gss_display_status (&min_stat, - error_status, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - if (sizeof(buf) > len + status_string.length + 1) { - snprintf(buf + len, sizeof(buf) - len, - ": %s", (char*) status_string.value); - len += status_string.length; - } - gss_release_buffer(&min_stat, &status_string); - } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); - - infof(conn->data, "%s", buf); -} - -int Curl_input_negotiate(struct connectdata *conn, char *header) -{ - struct negotiatedata *neg_ctx = &conn->data->state.negotiate; - OM_uint32 major_status, minor_status, minor_status2; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - int ret; - size_t len; - bool gss; - const char* protocol; - - while(*header && ISSPACE(*header)) - header++; - if(checkprefix("GSS-Negotiate", header)) { - protocol = "GSS-Negotiate"; - gss = TRUE; - } - else if (checkprefix("Negotiate", header)) { - protocol = "Negotiate"; - gss = FALSE; - } - else - return -1; - - if (neg_ctx->context) { - if (neg_ctx->gss != gss) { - return -1; - } - } - else { - neg_ctx->protocol = protocol; - neg_ctx->gss = gss; - } - - if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { - /* We finished succesfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_cleanup_negotiate(conn->data); - return -1; - } - - if (neg_ctx->server_name == NULL && - (ret = get_gss_name(conn, &neg_ctx->server_name))) - return ret; - - header += strlen(neg_ctx->protocol); - while(*header && ISSPACE(*header)) - header++; - - len = strlen(header); - if (len > 0) { - int rawlen = Curl_base64_decode(header, (unsigned char **)&input_token.value); - if (rawlen < 0) - return -1; - input_token.length = rawlen; - -#ifdef HAVE_SPNEGO /* Handle SPNEGO */ - if (checkprefix("Negotiate", header)) { - ASN1_OBJECT * object = NULL; - int rc = 1; - unsigned char * spnegoToken = NULL; - size_t spnegoTokenLength = 0; - unsigned char * mechToken = NULL; - size_t mechTokenLength = 0; - - spnegoToken = malloc(input_token.length); - if (input_token.value == NULL) - return ENOMEM; - spnegoTokenLength = input_token.length; - - object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); - if (!parseSpnegoTargetToken(spnegoToken, - spnegoTokenLength, - NULL, - NULL, - &mechToken, - &mechTokenLength, - NULL, - NULL)) { - free(spnegoToken); - spnegoToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token failed\n"); - } - else { - free(input_token.value); - input_token.value = NULL; - input_token.value = malloc(mechTokenLength); - memcpy(input_token.value, mechToken,mechTokenLength); - input_token.length = mechTokenLength; - free(mechToken); - mechToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); - } - } -#endif - } - - major_status = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, - &neg_ctx->context, - neg_ctx->server_name, - GSS_C_NO_OID, - GSS_C_DELEG_FLAG, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - NULL, - &output_token, - NULL, - NULL); - if (input_token.length > 0) - gss_release_buffer(&minor_status2, &input_token); - neg_ctx->status = major_status; - if (GSS_ERROR(major_status)) { - /* Curl_cleanup_negotiate(conn->data) ??? */ - log_gss_error(conn, minor_status, - (char *)"gss_init_sec_context() failed: "); - return -1; - } - - if (output_token.length == 0) { - return -1; - } - - neg_ctx->output_token = output_token; - /* conn->bits.close = FALSE; */ - - return 0; -} - - -CURLcode Curl_output_negotiate(struct connectdata *conn) -{ - struct negotiatedata *neg_ctx = &conn->data->state.negotiate; - OM_uint32 minor_status; - char *encoded = NULL; - int len; - -#ifdef HAVE_SPNEGO /* Handle SPNEGO */ - if (checkprefix("Negotiate",neg_ctx->protocol)) { - ASN1_OBJECT * object = NULL; - int rc = 1; - unsigned char * spnegoToken = NULL; - size_t spnegoTokenLength = 0; - unsigned char * responseToken = NULL; - size_t responseTokenLength = 0; - - responseToken = malloc(neg_ctx->output_token.length); - if ( responseToken == NULL) - return CURLE_OUT_OF_MEMORY; - memcpy(responseToken, neg_ctx->output_token.value, - neg_ctx->output_token.length); - responseTokenLength = neg_ctx->output_token.length; - - object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); - if (!makeSpnegoInitialToken (object, - responseToken, - responseTokenLength, - &spnegoToken, - &spnegoTokenLength)) { - free(responseToken); - responseToken = NULL; - infof(conn->data, "Make SPNEGO Initial Token failed\n"); - } - else { - free(neg_ctx->output_token.value); - responseToken = NULL; - neg_ctx->output_token.value = malloc(spnegoTokenLength); - memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength); - neg_ctx->output_token.length = spnegoTokenLength; - free(spnegoToken); - spnegoToken = NULL; - infof(conn->data, "Make SPNEGO Initial Token succeeded\n"); - } - } -#endif - len = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded); - - if (len < 0) - return CURLE_OUT_OF_MEMORY; - - conn->allocptr.userpwd = - aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded); - free(encoded); - gss_release_buffer(&minor_status, &neg_ctx->output_token); - return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; -} - -void Curl_cleanup_negotiate(struct SessionHandle *data) -{ - OM_uint32 minor_status; - struct negotiatedata *neg_ctx = &data->state.negotiate; - - if (neg_ctx->context != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER); - - if (neg_ctx->output_token.length != 0) - gss_release_buffer(&minor_status, &neg_ctx->output_token); - - if (neg_ctx->server_name != GSS_C_NO_NAME) - gss_release_name(&minor_status, &neg_ctx->server_name); - - memset(neg_ctx, 0, sizeof(*neg_ctx)); -} - - -#endif -#endif diff --git a/Utilities/cmcurl/http_negotiate.h b/Utilities/cmcurl/http_negotiate.h deleted file mode 100644 index ce0d083..0000000 --- a/Utilities/cmcurl/http_negotiate.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef __HTTP_NEGOTIATE_H -#define __HTTP_NEGOTIATE_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifdef HAVE_GSSAPI - -/* this is for Negotiate header input */ -int Curl_input_negotiate(struct connectdata *conn, char *header); - -/* this is for creating Negotiate header output */ -CURLcode Curl_output_negotiate(struct connectdata *conn); - -void Curl_cleanup_negotiate(struct SessionHandle *data); - -#endif - -#endif diff --git a/Utilities/cmcurl/http_ntlm.c b/Utilities/cmcurl/http_ntlm.c deleted file mode 100644 index aff1bb1..0000000 --- a/Utilities/cmcurl/http_ntlm.c +++ /dev/null @@ -1,1111 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#include "setup.h" - -/* NTLM details: - - http://davenport.sourceforge.net/ntlm.html - http://www.innovation.ch/java/ntlm.html - - Another implementation: - http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp - -*/ - -#ifndef CURL_DISABLE_HTTP -#ifdef USE_NTLM - -#define DEBUG_ME 0 - -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "urldata.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ -#include "sendf.h" -#include "strequal.h" -#include "base64.h" -#include "http_ntlm.h" -#include "url.h" -#include "memory.h" -#include "ssluse.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* "NTLMSSP" signature is always in ASCII regardless of the platform */ -#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" - -#ifndef USE_WINDOWS_SSPI - -#include -#include -#include -#include -#include - -#if OPENSSL_VERSION_NUMBER < 0x00907001L -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_odd_parity des_set_odd_parity -#define DES_set_key des_set_key -#define DES_ecb_encrypt des_ecb_encrypt - -/* This is how things were done in the old days */ -#define DESKEY(x) x -#define DESKEYARG(x) x -#else -/* Modern version */ -#define DESKEYARG(x) *x -#define DESKEY(x) &x -#endif - -#else - -#include - -/* Handle of security.dll or secur32.dll, depending on Windows version */ -static HMODULE s_hSecDll = NULL; -/* Pointer to SSPI dispatch table */ -static PSecurityFunctionTable s_pSecFn = NULL; - -#endif - -/* The last #include file should be: */ -#include "memdebug.h" - -/* Define this to make the type-3 message include the NT response message */ -#define USE_NTRESPONSES 1 - -/* Define this to make the type-3 message include the NTLM2Session response - message, requires USE_NTRESPONSES. */ -#define USE_NTLM2SESSION 1 - -#ifndef USE_WINDOWS_SSPI -/* this function converts from the little endian format used in the incoming - package to whatever endian format we're using natively */ -static unsigned int readint_le(unsigned char *buf) /* must point to a - 4 bytes buffer*/ -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | - ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); -} -#endif - -#if DEBUG_ME -# define DEBUG_OUT(x) x -static void print_flags(FILE *handle, unsigned long flags) -{ - if(flags & NTLMFLAG_NEGOTIATE_UNICODE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); - if(flags & NTLMFLAG_NEGOTIATE_OEM) - fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); - if(flags & NTLMFLAG_REQUEST_TARGET) - fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); - if(flags & (1<<3)) - fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); - if(flags & NTLMFLAG_NEGOTIATE_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); - if(flags & NTLMFLAG_NEGOTIATE_SEAL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); - if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); - if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_NETWARE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); - if(flags & (1<<10)) - fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); - if(flags & (1<<11)) - fprintf(handle, "NTLMFLAG_UNKNOWN_11 "); - if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); - if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); - if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); - if(flags & NTLMFLAG_TARGET_TYPE_SERVER) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); - if(flags & NTLMFLAG_TARGET_TYPE_SHARE) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); - if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) - fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) - fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); - if(flags & (1<<24)) - fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); - if(flags & (1<<25)) - fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); - if(flags & (1<<26)) - fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); - if(flags & (1<<27)) - fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); - if(flags & (1<<28)) - fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); - if(flags & NTLMFLAG_NEGOTIATE_128) - fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); - if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); - if(flags & NTLMFLAG_NEGOTIATE_56) - fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); -} - -static void print_hex(FILE *handle, const char *buf, size_t len) -{ - const char *p = buf; - fprintf(stderr, "0x"); - while (len-- > 0) - fprintf(stderr, "%02.2x", (unsigned int)*p++); -} -#else -# define DEBUG_OUT(x) -#endif - -/* - (*) = A "security buffer" is a triplet consisting of two shorts and one - long: - - 1. a 'short' containing the length of the buffer in bytes - 2. a 'short' containing the allocated space for the buffer in bytes - 3. a 'long' containing the offset to the start of the buffer from the - beginning of the NTLM message, in bytes. -*/ - - -CURLntlm Curl_input_ntlm(struct connectdata *conn, - bool proxy, /* if proxy or not */ - char *header) /* rest of the www-authenticate: - header */ -{ - /* point to the correct struct with this */ - struct ntlmdata *ntlm; -#ifndef USE_WINDOWS_SSPI - static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; -#endif - - ntlm = proxy?&conn->proxyntlm:&conn->ntlm; - - /* skip initial whitespaces */ - while(*header && ISSPACE(*header)) - header++; - - if(checkprefix("NTLM", header)) { - header += strlen("NTLM"); - - while(*header && ISSPACE(*header)) - header++; - - if(*header) { - /* We got a type-2 message here: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x02000000) - 12 Target Name security buffer(*) - 20 Flags long - 24 Challenge 8 bytes - (32) Context (optional) 8 bytes (two consecutive longs) - (40) Target Information (optional) security buffer(*) - 32 (48) start of data block - */ - size_t size; - unsigned char *buffer; - size = Curl_base64_decode(header, &buffer); - if(!buffer) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */ - -#ifdef USE_WINDOWS_SSPI - ntlm->type_2 = malloc(size+1); - if (ntlm->type_2 == NULL) { - free(buffer); - return CURLE_OUT_OF_MEMORY; - } - ntlm->n_type_2 = size; - memcpy(ntlm->type_2, buffer, size); -#else - ntlm->flags = 0; - - if((size < 32) || - (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || - (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) { - /* This was not a good enough type-2 message */ - free(buffer); - return CURLNTLM_BAD; - } - - ntlm->flags = readint_le(&buffer[20]); - memcpy(ntlm->nonce, &buffer[24], 8); - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n nonce="); - print_hex(stderr, (char *)ntlm->nonce, 8); - fprintf(stderr, "\n****\n"); - fprintf(stderr, "**** Header %s\n ", header); - }); - - free(buffer); -#endif - } - else { - if(ntlm->state >= NTLMSTATE_TYPE1) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */ - } - } - return CURLNTLM_FINE; -} - -#ifndef USE_WINDOWS_SSPI - -/* - * 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(unsigned char *key_56, - DES_key_schedule DESKEYARG(ks)) -{ - DES_cblock key; - - 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); - - DES_set_odd_parity(&key); - DES_set_key(&key, ks); -} - - /* - * takes a 21 byte array and treats it as 3 56-bit DES keys. The - * 8 byte plaintext is encrypted with each key and the resulting 24 - * bytes are stored in the results array. - */ -static void lm_resp(unsigned char *keys, - unsigned char *plaintext, - unsigned char *results) -{ - DES_key_schedule ks; - - setup_des_key(keys, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys+7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys+14, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), - DESKEY(ks), DES_ENCRYPT); -} - - -/* - * Set up lanmanager hashed password - */ -static void mk_lm_hash(struct SessionHandle *data, - char *password, - unsigned char *lmbuffer /* 21 bytes */) -{ - unsigned char pw[14]; - static const unsigned char magic[] = { - 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ - }; - unsigned int i; - size_t len = strlen(password); - - if (len > 14) - len = 14; - - for (i=0; itype_2) { - free(ntlm->type_2); - ntlm->type_2 = NULL; - } - if (ntlm->has_handles) { - s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - ntlm->has_handles = 0; - } - if (ntlm->p_identity) { - if (ntlm->identity.User) free(ntlm->identity.User); - if (ntlm->identity.Password) free(ntlm->identity.Password); - if (ntlm->identity.Domain) free(ntlm->identity.Domain); - ntlm->p_identity = NULL; - } -} - -#endif - -#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) -#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ - (((x) >>16)&0xff), (((x)>>24) & 0xff) - -#define HOSTNAME_MAX 1024 - -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, - bool proxy) -{ - const char *domain=""; /* empty */ - char host [HOSTNAME_MAX+ 1] = ""; /* empty */ -#ifndef USE_WINDOWS_SSPI - size_t domlen = strlen(domain); - size_t hostlen = strlen(host); - size_t hostoff; /* host name offset */ - size_t domoff; /* domain name offset */ -#endif - size_t size; - char *base64=NULL; - unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very - long */ - - /* point to the address of the pointer that holds the string to sent to the - server, which is for a plain host or for a HTTP proxy */ - char **allocuserpwd; - - /* point to the name and password for this */ - char *userp; - char *passwdp; - /* point to the correct struct with this */ - struct ntlmdata *ntlm; - struct auth *authp; - - curlassert(conn); - curlassert(conn->data); - - if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - ntlm = &conn->proxyntlm; - authp = &conn->data->state.authproxy; - } - else { - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - ntlm = &conn->ntlm; - authp = &conn->data->state.authhost; - } - authp->done = FALSE; - - /* not set means empty */ - if(!userp) - userp=(char *)""; - - if(!passwdp) - passwdp=(char *)""; - -#ifdef USE_WINDOWS_SSPI - /* If security interface is not yet initialized try to do this */ - if (s_hSecDll == NULL) { - /* Determine Windows version. Security functions are located in - * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP - * contain both these DLLs (security.dll just forwards calls to - * secur32.dll) - */ - OSVERSIONINFO osver; - osver.dwOSVersionInfoSize = sizeof(osver); - GetVersionEx(&osver); - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT - && osver.dwMajorVersion == 4) - s_hSecDll = LoadLibrary("security.dll"); - else - s_hSecDll = LoadLibrary("secur32.dll"); - if (s_hSecDll != NULL) { - INIT_SECURITY_INTERFACE pInitSecurityInterface; - pInitSecurityInterface = - (INIT_SECURITY_INTERFACE)GetProcAddress(s_hSecDll, - "InitSecurityInterfaceA"); - if (pInitSecurityInterface != NULL) - s_pSecFn = pInitSecurityInterface(); - } - } - if (s_pSecFn == NULL) - return CURLE_RECV_ERROR; -#endif - - switch(ntlm->state) { - case NTLMSTATE_TYPE1: - default: /* for the weird cases we (re)start here */ -#ifdef USE_WINDOWS_SSPI - { - SecBuffer buf; - SecBufferDesc desc; - SECURITY_STATUS status; - ULONG attrs; - const char *user; - int domlen; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - ntlm_sspi_cleanup(ntlm); - - user = strchr(userp, '\\'); - if (!user) - user = strchr(userp, '/'); - - if (user) { - domain = userp; - domlen = user - userp; - user++; - } - else { - user = userp; - domain = ""; - domlen = 0; - } - - if (user && *user) { - /* note: initialize all of this before doing the mallocs so that - * it can be cleaned up later without leaking memory. - */ - ntlm->p_identity = &ntlm->identity; - memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); - if ((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.UserLength = strlen(user); - if ((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.PasswordLength = strlen(passwdp); - if ((ntlm->identity.Domain = malloc(domlen+1)) == NULL) - return CURLE_OUT_OF_MEMORY; - strncpy((char *)ntlm->identity.Domain, domain, domlen); - ntlm->identity.Domain[domlen] = '\0'; - ntlm->identity.DomainLength = domlen; - ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; - } - else { - ntlm->p_identity = NULL; - } - - if (s_pSecFn->AcquireCredentialsHandle( - NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, - NULL, NULL, &ntlm->handle, &tsDummy - ) != SEC_E_OK) { - return CURLE_OUT_OF_MEMORY; - } - - desc.ulVersion = SECBUFFER_VERSION; - desc.cBuffers = 1; - desc.pBuffers = &buf; - buf.cbBuffer = sizeof(ntlmbuf); - buf.BufferType = SECBUFFER_TOKEN; - buf.pvBuffer = ntlmbuf; - - status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - NULL, 0, - &ntlm->c_handle, &desc, - &attrs, &tsDummy); - - if (status == SEC_I_COMPLETE_AND_CONTINUE || - status == SEC_I_CONTINUE_NEEDED) { - s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); - } - else if (status != SEC_E_OK) { - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - return CURLE_RECV_ERROR; - } - - ntlm->has_handles = 1; - size = buf.cbBuffer; - } -#else - hostoff = 0; - domoff = hostoff + hostlen; /* This is 0: remember that host and domain - are empty */ - - /* Create and send a type-1 message: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x01000000) - 12 Flags long - 16 Supplied Domain security buffer(*) - 24 Supplied Workstation security buffer(*) - 32 start of data block - - */ -#if USE_NTLM2SESSION -#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY -#else -#define NTLM2FLAG 0 -#endif - snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c" - "\x01%c%c%c" /* 32-bit type = 1 */ - "%c%c%c%c" /* 32-bit NTLM flag field */ - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host name offset */ - "%c%c" /* 2 zeroes */ - "%s" /* host name */ - "%s", /* domain string */ - 0, /* trailing zero */ - 0,0,0, /* part of type-1 long */ - - LONGQUARTET( - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN - ), - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0,0, - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0,0, - host /* this is empty */, domain /* this is empty */); - - /* initial packet length */ - size = 32 + hostlen + domlen; -#endif - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - print_flags(stderr, - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - fprintf(stderr, "\n****\n"); - }); - - /* now size is the size of the base64 encoded package size */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - break; - - case NTLMSTATE_TYPE2: - /* We received the type-2 message already, create a type-3 message: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x03000000) - 12 LM/LMv2 Response security buffer(*) - 20 NTLM/NTLMv2 Response security buffer(*) - 28 Domain Name security buffer(*) - 36 User Name security buffer(*) - 44 Workstation Name security buffer(*) - (52) Session Key (optional) security buffer(*) - (60) Flags (optional) long - 52 (64) start of data block - - */ - - { -#ifdef USE_WINDOWS_SSPI - SecBuffer type_2, type_3; - SecBufferDesc type_2_desc, type_3_desc; - SECURITY_STATUS status; - ULONG attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = type_3_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2; - type_3_desc.pBuffers = &type_3; - - type_2.BufferType = SECBUFFER_TOKEN; - type_2.pvBuffer = ntlm->type_2; - type_2.cbBuffer = ntlm->n_type_2; - type_3.BufferType = SECBUFFER_TOKEN; - type_3.pvBuffer = ntlmbuf; - type_3.cbBuffer = sizeof(ntlmbuf); - - status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, &ntlm->c_handle, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, &type_2_desc, - 0, &ntlm->c_handle, &type_3_desc, - &attrs, &tsDummy); - - if (status != SEC_E_OK) - return CURLE_RECV_ERROR; - - size = type_3.cbBuffer; - - ntlm_sspi_cleanup(ntlm); - -#else - int lmrespoff; - unsigned char lmresp[24]; /* fixed-size */ -#if USE_NTRESPONSES - int ntrespoff; - unsigned char ntresp[24]; /* fixed-size */ -#endif - size_t useroff; - const char *user; - size_t userlen; - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if (user) { - domain = userp; - domlen = (user - domain); - user++; - } - else - user = userp; - userlen = strlen(user); - - if (gethostname(host, HOSTNAME_MAX)) { - infof(conn->data, "gethostname() failed, continuing without!"); - hostlen = 0; - } - else { - /* If the workstation if configured with a full DNS name (i.e. - * workstation.somewhere.net) gethostname() returns the fully qualified - * name, which NTLM doesn't like. - */ - char *dot = strchr(host, '.'); - if (dot) - *dot = '\0'; - hostlen = strlen(host); - } - -#if USE_NTLM2SESSION - /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ - if (ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { - unsigned char ntbuffer[0x18]; - unsigned char tmp[0x18]; - unsigned char md5sum[MD5_DIGEST_LENGTH]; - MD5_CTX MD5; - unsigned char random[8]; - - /* Need to create 8 bytes random data */ - Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */ - RAND_bytes(random,8); - - /* 8 bytes random data as challenge in lmresp */ - memcpy(lmresp,random,8); - /* Pad with zeros */ - memset(lmresp+8,0,0x10); - - /* Fill tmp with challenge(nonce?) + random */ - memcpy(tmp,&ntlm->nonce[0],8); - memcpy(tmp+8,random,8); - - MD5_Init(&MD5); - MD5_Update(&MD5, tmp, 16); - MD5_Final(md5sum, &MD5); - /* We shall only use the first 8 bytes of md5sum, - but the des code in lm_resp only encrypt the first 8 bytes */ - mk_nt_hash(conn->data, passwdp, ntbuffer); - lm_resp(ntbuffer, md5sum, ntresp); - - /* End of NTLM2 Session code */ - } - else { -#endif - -#if USE_NTRESPONSES - unsigned char ntbuffer[0x18]; -#endif - unsigned char lmbuffer[0x18]; - -#if USE_NTRESPONSES - mk_nt_hash(conn->data, passwdp, ntbuffer); - lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); -#endif - - mk_lm_hash(conn->data, passwdp, lmbuffer); - lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); - /* A safer but less compatible alternative is: - * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ -#if USE_NTLM2SESSION - } -#endif - - lmrespoff = 64; /* size of the message header */ -#if USE_NTRESPONSES - ntrespoff = lmrespoff + 0x18; - domoff = ntrespoff + 0x18; -#else - domoff = lmrespoff + 0x18; -#endif - useroff = domoff + domlen; - hostoff = useroff + userlen; - - /* Create the big type-3 message binary blob */ - size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf), - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* type-3, 32 bits */ - - "%c%c" /* LanManager length */ - "%c%c" /* LanManager allocated space */ - "%c%c" /* LanManager offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* NT-response length */ - "%c%c" /* NT-response allocated space */ - "%c%c" /* NT-response offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* user length */ - "%c%c" /* user allocated space */ - "%c%c" /* user offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* session key length (unknown purpose) */ - "%c%c" /* session key allocated space (unknown purpose) */ - "%c%c" /* session key offset (unknown purpose) */ - "%c%c" /* 2 zeroes */ - - "%c%c%c%c" /* flags */ - - /* domain string */ - /* user string */ - /* host string */ - /* LanManager response */ - /* NT response */ - , - 0, /* zero termination */ - 0,0,0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, - -#if USE_NTRESPONSES - SHORTPAIR(0x18), /* NT-response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(ntrespoff), - 0x0, 0x0, -#else - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, -#endif - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0x0, 0x0, - - SHORTPAIR(userlen), - SHORTPAIR(userlen), - SHORTPAIR(useroff), - 0x0, 0x0, - - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0x0, 0x0, - - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - - LONGQUARTET(ntlm->flags)); - DEBUG_OUT(assert(size==64)); - - DEBUG_OUT(assert(size == lmrespoff)); - /* We append the binary hashes */ - if(size < (sizeof(ntlmbuf) - 0x18)) { - memcpy(&ntlmbuf[size], lmresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE3 header lmresp="); - print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); - }); - -#if USE_NTRESPONSES - if(size < (sizeof(ntlmbuf) - 0x18)) { - DEBUG_OUT(assert(size == ntrespoff)); - memcpy(&ntlmbuf[size], ntresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "\n ntresp="); - print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); - }); - -#endif - - DEBUG_OUT({ - fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(ntlm->flags), ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n****\n"); - }); - - - /* Make sure that the domain, user and host strings fit in the target - buffer before we copy them there. */ - if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) { - failf(conn->data, "user + domain + host name too big"); - return CURLE_OUT_OF_MEMORY; - } - - curlassert(size == domoff); - memcpy(&ntlmbuf[size], domain, domlen); - size += domlen; - - curlassert(size == useroff); - memcpy(&ntlmbuf[size], user, userlen); - size += userlen; - - curlassert(size == hostoff); - memcpy(&ntlmbuf[size], host, hostlen); - size += hostlen; - -#ifdef CURL_DOES_CONVERSIONS - /* convert domain, user, and host to ASCII but leave the rest as-is */ - if(CURLE_OK != Curl_convert_to_network(conn->data, - (char *)&ntlmbuf[domoff], - size-domoff)) { - return CURLE_CONV_FAILED; - } -#endif /* CURL_DOES_CONVERSIONS */ - -#endif - - /* convert the binary blob into base64 */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ - authp->done = TRUE; - } - break; - - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - if(*allocuserpwd) { - free(*allocuserpwd); - *allocuserpwd=NULL; - } - authp->done = TRUE; - break; - } - - return CURLE_OK; -} - - -void -Curl_ntlm_cleanup(struct connectdata *conn) -{ -#ifdef USE_WINDOWS_SSPI - ntlm_sspi_cleanup(&conn->ntlm); - ntlm_sspi_cleanup(&conn->proxyntlm); - if (s_hSecDll != NULL) { - FreeLibrary(s_hSecDll); - s_hSecDll = NULL; - s_pSecFn = NULL; - } -#else - (void)conn; -#endif -} - -#endif /* USE_NTLM */ -#endif /* !CURL_DISABLE_HTTP */ diff --git a/Utilities/cmcurl/http_ntlm.h b/Utilities/cmcurl/http_ntlm.h deleted file mode 100644 index a8de220..0000000 --- a/Utilities/cmcurl/http_ntlm.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef __HTTP_NTLM_H -#define __HTTP_NTLM_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -typedef enum { - CURLNTLM_NONE, /* not a ntlm */ - CURLNTLM_BAD, /* an ntlm, but one we don't like */ - CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */ - CURLNTLM_FINE, /* an ntlm we act on */ - - CURLNTLM_LAST /* last entry in this enum, don't use */ -} CURLntlm; - -/* this is for ntlm header input */ -CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header); - -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); - -void Curl_ntlm_cleanup(struct connectdata *conn); -#ifndef USE_NTLM -#define Curl_ntlm_cleanup(x) -#endif - - -/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ - -#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) -/* Indicates that Unicode strings are supported for use in security buffer - data. */ - -#define NTLMFLAG_NEGOTIATE_OEM (1<<1) -/* Indicates that OEM strings are supported for use in security buffer data. */ - -#define NTLMFLAG_REQUEST_TARGET (1<<2) -/* Requests that the server's authentication realm be included in the Type 2 - message. */ - -/* unknown (1<<3) */ -#define NTLMFLAG_NEGOTIATE_SIGN (1<<4) -/* Specifies that authenticated communication between the client and server - should carry a digital signature (message integrity). */ - -#define NTLMFLAG_NEGOTIATE_SEAL (1<<5) -/* Specifies that authenticated communication between the client and server - should be encrypted (message confidentiality). */ - -#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6) -/* unknown purpose */ - -#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7) -/* Indicates that the LAN Manager session key should be used for signing and - sealing authenticated communications. */ - -#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8) -/* unknown purpose */ - -#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9) -/* Indicates that NTLM authentication is being used. */ - -/* unknown (1<<10) */ -/* unknown (1<<11) */ - -#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12) -/* Sent by the client in the Type 1 message to indicate that a desired - authentication realm is included in the message. */ - -#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13) -/* Sent by the client in the Type 1 message to indicate that the client - workstation's name is included in the message. */ - -#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14) -/* Sent by the server to indicate that the server and client are on the same - machine. Implies that the client may use a pre-established local security - context rather than responding to the challenge. */ - -#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15) -/* Indicates that authenticated communication between the client and server - should be signed with a "dummy" signature. */ - -#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16) -/* Sent by the server in the Type 2 message to indicate that the target - authentication realm is a domain. */ - -#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17) -/* Sent by the server in the Type 2 message to indicate that the target - authentication realm is a server. */ - -#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18) -/* Sent by the server in the Type 2 message to indicate that the target - authentication realm is a share. Presumably, this is for share-level - authentication. Usage is unclear. */ - -#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19) -/* Indicates that the NTLM2 signing and sealing scheme should be used for - protecting authenticated communications. */ - -#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20) -/* unknown purpose */ - -#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21) -/* unknown purpose */ - -#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22) -/* unknown purpose */ - -#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23) -/* Sent by the server in the Type 2 message to indicate that it is including a - Target Information block in the message. */ - -/* unknown (1<24) */ -/* unknown (1<25) */ -/* unknown (1<26) */ -/* unknown (1<27) */ -/* unknown (1<28) */ - -#define NTLMFLAG_NEGOTIATE_128 (1<<29) -/* Indicates that 128-bit encryption is supported. */ - -#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30) -/* unknown purpose */ - -#define NTLMFLAG_NEGOTIATE_56 (1<<31) -/* Indicates that 56-bit encryption is supported. */ -#endif diff --git a/Utilities/cmcurl/if2ip.c b/Utilities/cmcurl/if2ip.c deleted file mode 100644 index b4a98c6..0000000 --- a/Utilities/cmcurl/if2ip.c +++ /dev/null @@ -1,134 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "if2ip.h" - -/* - * This test can probably be simplified to #if defined(SIOCGIFADDR) and - * moved after the following includes. - */ -#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN__) && \ - !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE) && \ - !defined(_AMIGASF) && !defined(__minix) - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -/* This must be before net/if.h for AIX 3.2 to enjoy life */ -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_SYS_SOCKIO_H -#include -#endif - -#ifdef VMS -#include -#endif - -#include "inet_ntop.h" -#include "memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#define SYS_ERROR -1 - -char *Curl_if2ip(const char *interface, char *buf, int buf_size) -{ - int dummy; - char *ip=NULL; - - if(!interface) - return NULL; - - dummy = socket(AF_INET, SOCK_STREAM, 0); - if (SYS_ERROR == dummy) { - return NULL; - } - else { - struct ifreq req; - size_t len = strlen(interface); - memset(&req, 0, sizeof(req)); - if(len >= sizeof(req.ifr_name)) - return NULL; /* this can't be a fine interface name */ - memcpy(req.ifr_name, interface, len+1); - req.ifr_addr.sa_family = AF_INET; -#ifdef IOCTL_3_ARGS - if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) { -#else - if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) { -#endif - sclose(dummy); - return NULL; - } - else { - struct in_addr in; - - struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr; - memcpy(&in, &s->sin_addr, sizeof(in)); - ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size); - } - sclose(dummy); - } - return ip; -} - -/* -- end of if2ip() -- */ -#else -char *Curl_if2ip(const char *interf, char *buf, int buf_size) -{ - (void) interf; - (void) buf; - (void) buf_size; - return NULL; -} -#endif diff --git a/Utilities/cmcurl/if2ip.h b/Utilities/cmcurl/if2ip.h deleted file mode 100644 index 4e86e2b..0000000 --- a/Utilities/cmcurl/if2ip.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __IF2IP_H -#define __IF2IP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#include "setup.h" - -extern char *Curl_if2ip(const char *interf, char *buf, int buf_size); - -#ifdef __INTERIX -#include - -/* Nedelcho Stanev's work-around for SFU 3.0 */ -struct ifreq { -#define IFNAMSIZ 16 -#define IFHWADDRLEN 6 - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - int ifru_metric; - int ifru_mtu; - } ifr_ifru; -}; - -/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the - C code. */ -#define ifr_dstaddr ifr_addr - -#define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define ifr_addr ifr_ifru.ifru_addr /* address */ -#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ -#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ -#define ifr_flags ifr_ifru.ifru_flags /* flags */ -#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ -#define ifr_metric ifr_ifru.ifru_metric /* metric */ -#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ - -#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ -#endif /* interix */ - -#endif diff --git a/Utilities/cmcurl/include/ca-bundle.h b/Utilities/cmcurl/include/ca-bundle.h new file mode 100644 index 0000000..12390bc --- /dev/null +++ b/Utilities/cmcurl/include/ca-bundle.h @@ -0,0 +1 @@ +/* ca bundle path set in here*/ diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h new file mode 100644 index 0000000..e586c4a --- /dev/null +++ b/Utilities/cmcurl/include/curl/curl.h @@ -0,0 +1,1644 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* If you have problems, all libcurl docs and details are found here: + http://curl.haxx.se/libcurl/ +*/ + +#include "curlver.h" /* the libcurl version defines */ + +#include +#include + +/* The include stuff here below is mainly for time_t! */ +#ifdef vms +# include +# include +#else +# include +# include +#endif /* defined (vms) */ + +typedef void CURL; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Decorate exportable functions for Win32 DLL linking. + * This avoids using a .def file for building libcurl.dll. + */ +#if (defined(WIN32) || defined(_WIN32)) && !defined(CURL_STATICLIB) +#if defined(BUILDING_LIBCURL) +#define CURL_EXTERN __declspec(dllexport) +#else +#define CURL_EXTERN __declspec(dllimport) +#endif +#else + +#ifdef CURL_HIDDEN_SYMBOLS +/* + * This definition is used to make external definitions visibile in the + * shared library when symbols are hidden by default. It makes no + * difference when compiling applications whether this is set or not, + * only when compiling the library. + */ +#define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +#define CURL_EXTERN +#endif +#endif + +/* + * We want the typedef curl_off_t setup for large file support on all + * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf + * format strings when outputting a variable of type curl_off_t. + * + * Note: "pocc -Ze" is MSVC compatibily mode and this sets _MSC_VER! + */ + +#if (defined(_MSC_VER) && !defined(__POCC__)) || (defined(__LCC__) && defined(WIN32)) +/* MSVC */ +#ifdef _WIN32_WCE + typedef long curl_off_t; +#define CURL_FORMAT_OFF_T "%ld" +#else + typedef signed __int64 curl_off_t; +#define CURL_FORMAT_OFF_T "%I64d" +#endif +#else /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */ +#if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__) +/* gcc on windows or Watcom */ + typedef long long curl_off_t; +#define CURL_FORMAT_OFF_T "%I64d" +#else /* GCC or Watcom on Windows */ + +/* "normal" POSIX approach, do note that this does not necessarily mean that + the type is >32 bits, see the SIZEOF_CURL_OFF_T define for that! */ + typedef off_t curl_off_t; + +/* Check a range of defines to detect large file support. On Linux it seems + none of these are set by default, so if you don't explicitly switches on + large file support, this define will be made for "small file" support. */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 /* to prevent warnings in the check below */ +#define UNDEF_FILE_OFFSET_BITS +#endif +#ifndef FILESIZEBITS +#define FILESIZEBITS 0 /* to prevent warnings in the check below */ +#define UNDEF_FILESIZEBITS +#endif + +#if defined(_LARGE_FILES) || (_FILE_OFFSET_BITS > 32) || (FILESIZEBITS > 32) \ + || defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE) + /* For now, we assume at least one of these to be set for large files to + work! */ +#define CURL_FORMAT_OFF_T "%lld" +#else /* LARGE_FILE support */ +#define CURL_FORMAT_OFF_T "%ld" +#endif +#endif /* GCC or Watcom on Windows */ +#endif /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */ + +#ifdef UNDEF_FILE_OFFSET_BITS +/* this was defined above for our checks, undefine it again */ +#undef _FILE_OFFSET_BITS +#endif + +#ifdef UNDEF_FILESIZEBITS +/* this was defined above for our checks, undefine it again */ +#undef FILESIZEBITS +#endif + +#if defined(_WIN32) && !defined(WIN32) +/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we + make this adjustment to catch this. */ +#define WIN32 1 +#endif + +#ifdef __cplusplus +} +#endif + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \ + !defined(__CYGWIN__) || defined(__MINGW32__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#endif +#else + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on system that are known to + require it! */ +#if defined(_AIX) || defined(NETWARE) || defined(__NetBSD__) || defined(__minix) +#include +#endif + +#ifndef _WIN32_WCE +#include +#endif +#ifndef __WATCOMC__ +#include +#endif +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#ifdef WIN32 +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ +#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ +#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ +#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer + do not free in formfree */ +#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer + do not free in formfree */ +#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ +#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ +}; + +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. */ +#define CURL_MAX_WRITE_SIZE 16384 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +#ifndef CURL_NO_OLDIES + /* not used since 7.10.8, will be removed in a future release */ +typedef int (*curl_passwd_callback)(void *clientp, + const char *prompt, + char *buffer, + int buflen); +#endif + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * 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. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_FTP_ACCESS_DENIED, /* 9 a service was denied by the FTP server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 - NOT USED */ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_WEIRD_USER_REPLY, /* 12 */ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_FTP_CANT_RECONNECT, /* 16 */ + CURLE_FTP_COULDNT_SET_BINARY, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_FTP_WRITE_ERROR, /* 20 */ + CURLE_FTP_QUOTE_ERROR, /* 21 */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_MALFORMAT_USER, /* 24 - NOT USED */ + CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */ + CURLE_READ_ERROR, /* 26 - could open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEOUTED, /* 28 - the timeout time was reached */ + CURLE_FTP_COULDNT_SET_ASCII, /* 29 - TYPE A failed */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_FTP_COULDNT_GET_SIZE, /* 32 - the SIZE command failed */ + CURLE_HTTP_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 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_LIBRARY_NOT_FOUND, /* 40 */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_BAD_CALLING_ORDER, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_BAD_PASSWORD_ENTERED, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_OBSOLETE, /* 50 - NOT USED */ + CURLE_SSL_PEER_CERTIFICATE, /* 51 - peer's certificate wasn't ok */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_SHARE_IN_USE, /* 57 - share is in use */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_FTP_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_TFTP_DISKFULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_TFTP_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURL_LAST /* never use! */ +} CURLcode; + +/* This prototype applies to all conversion callbacks */ +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 SSL_CTX */ + void *userptr); + +/* Make a spelling correction for the operation timed-out define */ +#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ +/* backwards compatibility with older names */ +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#endif + +typedef enum { + CURLPROXY_HTTP = 0, + CURLPROXY_SOCKS4 = 4, + CURLPROXY_SOCKS5 = 5 +} curl_proxytype; + +#define CURLAUTH_NONE 0 /* nothing */ +#define CURLAUTH_BASIC (1<<0) /* Basic (default) */ +#define CURLAUTH_DIGEST (1<<1) /* Digest */ +#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */ +#define CURLAUTH_NTLM (1<<3) /* NTLM */ +#define CURLAUTH_ANY ~0 /* all types set */ +#define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ +/* this was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* These are just to make older programs not break: */ +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME +#endif + +#define CURL_ERROR_SIZE 256 + +/* parameter for the CURLOPT_FTP_SSL option */ +typedef enum { + CURLFTPSSL_NONE, /* do not attempt to use SSL */ + CURLFTPSSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLFTPSSL_CONTROL, /* SSL for the control connection or fail */ + CURLFTPSSL_ALL, /* SSL for all communication or fail */ + CURLFTPSSL_LAST /* not an option, never use */ +} curl_ftpssl; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif +/* + * Figure out if we can use the ## operator, which is supported by ISO/ANSI C + * and C++. Some compilers support it without setting __STDC__ or __cplusplus + * so we need to carefully check for them too. We don't use configure-checks + * for these since we want these headers to remain generic and working for all + * platforms. + */ +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +#ifdef CURL_ISOCPP +#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(FILE, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, OBJECTPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, OBJECTPOINT, 4), + + /* "name:password" to use when fetching. */ + CINIT(USERPWD, OBJECTPOINT, 5), + + /* "name:password" to use with proxy. */ + CINIT(PROXYUSERPWD, OBJECTPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, OBJECTPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(INFILE, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was succcessful. -1 means + * unknown size. + * + * 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. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referer page (needed by some CGIs) */ + CINIT(REFERER, OBJECTPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, OBJECTPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, OBJECTPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG , 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * 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. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, OBJECTPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct HttpPost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, OBJECTPOINT, 25), + + /* password for the SSL-private key, keep this for compatibility */ + CINIT(SSLCERTPASSWD, OBJECTPOINT, 26), + /* password for the SSL private key */ + CINIT(SSLKEYPASSWD, OBJECTPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(WRITEHEADER, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, OBJECTPOINT, 31), + + /* What version to specifly try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), + + /* HTTP request, for odd commands like DELETE, TRACE and others */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + /* Pass a pointer to string of the output using full variable-replacement + as described elsewhere. */ + CINIT(WRITEINFO, OBJECTPOINT, 40), + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(FTPLISTONLY, LONG, 48), /* Use NLST when listing ftp dir */ + + CINIT(FTPAPPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the progress callback */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), + + /* We want the referer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, OBJECTPOINT, 62), + + /* Set the krb4 security level, this also enables krb4 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. */ + CINIT(KRB4LEVEL, OBJECTPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, OBJECTPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + /* What policy to use when closing connections when the cache is filled + up */ + CINIT(CLOSEPOLICY, LONG, 72), + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + 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. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, OBJECTPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, OBJECTPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects + are OK within this time, then fine... This only aborts the connect + phase. [Only works on unix-style/SIGALRM operating systems] */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, OBJECTPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specificly switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, OBJECTPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, OBJECTPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, OBJECTPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, OBJECTPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To becomeO BSOLETE soon */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands (Wesley Laxton)*/ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, OBJECTPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4 and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. */ + CINIT(ENCODING, OBJECTPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentionally send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specificly switch on or off the FTP engine's use of the EPRT command ( it + also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG , 112), + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + 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. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, 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. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* 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. */ + CINIT(NETRC_FILE, OBJECTPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise + CURLFTPSSL_CONTROL - SSL for the control connection or fail + CURLFTPSSL_ALL - SSL for all communication or fail + */ + CINIT(FTP_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_FTP_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), + + /* feed cookies into cookie engine */ + CINIT(COOKIELIST, OBJECTPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_WRITEDATA CURLOPT_FILE +#define CURLOPT_READDATA CURLOPT_INFILE +#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + 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_LAST /* *ILLEGAL* http version */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +#ifdef __cplusplus +} +#endif + +#if defined __BEOS__ || defined __HAIKU__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CURLFORM_LASTENTRY /* the last unusued */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanved function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * 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 + * 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 + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 30 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internaly to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + +typedef void CURLSH; + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* out of memory */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify shich data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basicly all programs ever, that want to get version information. It is + 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_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */ +#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */ +#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ +#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ +#define CURL_VERSION_CONV (1<<12) /* character conversions are + supported */ + +/* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +#endif /* __CURL_CURL_H */ diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h new file mode 100644 index 0000000..9380022 --- /dev/null +++ b/Utilities/cmcurl/include/curl/curlver.h @@ -0,0 +1,56 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.16.1" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 16 +#define LIBCURL_VERSION_PATCH 1 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + 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 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. +*/ +#define LIBCURL_VERSION_NUM 0x071001 + +#endif /* __CURL_CURLVER_H */ diff --git a/Utilities/cmcurl/include/curl/easy.h b/Utilities/cmcurl/include/curl/easy.h new file mode 100644 index 0000000..17de210 --- /dev/null +++ b/Utilities/cmcurl/include/curl/easy.h @@ -0,0 +1,81 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). 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 is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistant connections cannot + * be transfered. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Utilities/cmcurl/include/curl/mprintf.h b/Utilities/cmcurl/include/curl/mprintf.h new file mode 100644 index 0000000..5c52688 --- /dev/null +++ b/Utilities/cmcurl/include/curl/mprintf.h @@ -0,0 +1,80 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include +#include /* needed for FILE */ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef _MPRINTF_REPLACE +# undef printf +# undef fprintf +# undef sprintf +# undef vsprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +#ifdef CURLDEBUG +/* When built with CURLDEBUG we define away the sprintf() functions since we + don't want internal code to be using them */ +# define sprintf sprintf_was_used +# define vsprintf vsprintf_was_used +#else +# define sprintf curl_msprintf +# define vsprintf curl_mvsprintf +#endif +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h new file mode 100644 index 0000000..1b66747 --- /dev/null +++ b/Utilities/cmcurl/include/curl/multi.h @@ -0,0 +1,327 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURLM; + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + 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'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 */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + + /* + * Name: curl_multi_perform() + * + * 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 + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * 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. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * 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'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 + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * 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 + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * 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 man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,number) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + number +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/Utilities/cmcurl/include/curl/stdcheaders.h b/Utilities/cmcurl/include/curl/stdcheaders.h new file mode 100644 index 0000000..11c1e2f --- /dev/null +++ b/Utilities/cmcurl/include/curl/stdcheaders.h @@ -0,0 +1,34 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif diff --git a/Utilities/cmcurl/include/curl/types.h b/Utilities/cmcurl/include/curl/types.h new file mode 100644 index 0000000..d37d6ae --- /dev/null +++ b/Utilities/cmcurl/include/curl/types.h @@ -0,0 +1 @@ +/* not used */ diff --git a/Utilities/cmcurl/inet_ntoa_r.h b/Utilities/cmcurl/inet_ntoa_r.h deleted file mode 100644 index c6c9bd8..0000000 --- a/Utilities/cmcurl/inet_ntoa_r.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __INET_NTOA_R_H -#define __INET_NTOA_R_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifdef HAVE_INET_NTOA_R_2_ARGS -/* - * uClibc 0.9.26 (at least) doesn't define this prototype. The buffer - * must be at least 16 characters long. - */ -char *inet_ntoa_r(const struct in_addr in, char buffer[]); - -#else -/* - * My solaris 5.6 system running gcc 2.8.1 does *not* have this prototype - * in any system include file! Isn't that weird? - */ -char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen); - -#endif - -#endif diff --git a/Utilities/cmcurl/inet_ntop.c b/Utilities/cmcurl/inet_ntop.c deleted file mode 100644 index 9381963..0000000 --- a/Utilities/cmcurl/inet_ntop.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 1996-2001 Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM - * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING - * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Original code by Paul Vixie. "curlified" by Gisle Vanem. - */ - -#include "setup.h" - -#ifndef HAVE_INET_NTOP - -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#include -#include - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "inet_ntop.h" - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -/* this platform has a inet_ntoa_r() function, but no proto declared anywhere - so we include our own proto to make compilers happy */ -#include "inet_ntoa_r.h" -#endif - -#define IN6ADDRSZ 16 -#define INADDRSZ 4 -#define INT16SZ 2 - -#ifdef USE_WINSOCK -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#define SET_ERRNO(e) WSASetLastError(errno = (e)) -#else -#define SET_ERRNO(e) errno = e -#endif - -/* - * Format an IPv4 address, more or less like inet_ntoa(). - * - * Returns `dst' (as a const) - * Note: - * - 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) -{ -#if defined(HAVE_INET_NTOA_R_2_ARGS) - const char *ptr; - curlassert(size >= 16); - ptr = inet_ntoa_r(*(struct in_addr*)src, dst); - return (char *)memmove(dst, ptr, strlen(ptr)+1); - -#elif defined(HAVE_INET_NTOA_R) - return inet_ntoa_r(*(struct in_addr*)src, dst, size); - -#else - const char *addr = inet_ntoa(*(struct in_addr*)src); - - if (strlen(addr) >= size) - { - SET_ERRNO(ENOSPC); - return (NULL); - } - return strcpy(dst, addr); -#endif -} - -#ifdef ENABLE_IPV6 -/* - * Convert IPv6 binary address into presentation (printable) format. - */ -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 - * 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. - */ - char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; - char *tp; - struct { - long base; - long len; - } best, cur; - unsigned long words[IN6ADDRSZ / INT16SZ]; - int i; - - /* Preprocess: - * Copy the input (bytewise) array into a wordwise array. - * Find the longest run of 0x00's in src[] for :: shorthanding. - */ - memset(words, '\0', sizeof(words)); - for (i = 0; i < IN6ADDRSZ; i++) - words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); - - best.base = -1; - cur.base = -1; - best.len = 0; - cur.len = 0; - - for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) - { - if (words[i] == 0) - { - if (cur.base == -1) - cur.base = i, cur.len = 1; - else - cur.len++; - } - else if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - cur.base = -1; - } - } - if ((cur.base != -1) && (best.base == -1 || cur.len > best.len)) - best = cur; - if (best.base != -1 && best.len < 2) - best.base = -1; - - /* Format the result. - */ - tp = tmp; - for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) - { - /* Are we inside the best run of 0x00's? - */ - if (best.base != -1 && i >= best.base && i < (best.base + best.len)) - { - if (i == best.base) - *tp++ = ':'; - continue; - } - - /* Are we following an initial run of 0x00s or any real hex? - */ - if (i != 0) - *tp++ = ':'; - - /* Is this address an encapsulated IPv4? - */ - if (i == 6 && best.base == 0 && - (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) - { - if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) - { - SET_ERRNO(ENOSPC); - return (NULL); - } - tp += strlen(tp); - break; - } - tp += snprintf(tp, 5, "%lx", words[i]); - } - - /* Was it a trailing run of 0x00's? - */ - if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) - *tp++ = ':'; - *tp++ = '\0'; - - /* Check for overflow, copy, and we're done. - */ - if ((size_t)(tp - tmp) > size) - { - SET_ERRNO(ENOSPC); - return (NULL); - } - return strcpy (dst, tmp); -} -#endif /* ENABLE_IPV6 */ - -/* - * Convert a network format address to presentation format. - * - * Returns pointer to presentation format address (`buf'), - * Returns NULL on error (see errno). - */ -char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) -{ - switch (af) { - case AF_INET: - return inet_ntop4((const unsigned char*)src, buf, size); -#ifdef ENABLE_IPV6 - case AF_INET6: - return inet_ntop6((const unsigned char*)src, buf, size); -#endif - default: - SET_ERRNO(EAFNOSUPPORT); - return NULL; - } -} -#endif /* HAVE_INET_NTOP */ diff --git a/Utilities/cmcurl/inet_ntop.h b/Utilities/cmcurl/inet_ntop.h deleted file mode 100644 index 54d64bd..0000000 --- a/Utilities/cmcurl/inet_ntop.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __INET_NTOP_H -#define __INET_NTOP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); - -#ifdef HAVE_INET_NTOP -#ifdef HAVE_ARPA_INET_H -#include -#endif -#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size) -#endif - -#endif /* __INET_NTOP_H */ diff --git a/Utilities/cmcurl/inet_pton.c b/Utilities/cmcurl/inet_pton.c deleted file mode 100644 index 9b9f88b..0000000 --- a/Utilities/cmcurl/inet_pton.c +++ /dev/null @@ -1,241 +0,0 @@ -/* This is from the BIND 4.9.4 release, modified to compile by itself */ - -/* Copyright (c) 1996 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -#include "setup.h" - -#ifndef HAVE_INET_PTON - -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#include -#include - -#include "inet_pton.h" - -#define IN6ADDRSZ 16 -#define INADDRSZ 4 -#define INT16SZ 2 - -#ifdef USE_WINSOCK -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#endif - -/* - * 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); -#ifdef ENABLE_IPV6 -static int inet_pton6(const char *src, unsigned char *dst); -#endif - -/* int - * inet_pton(af, src, dst) - * convert from presentation format (which usually means ASCII printable) - * 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 wasn't valid (`dst' is untouched in this case) - * -1 if some other error occurred (`dst' is untouched in this case, too) - * author: - * Paul Vixie, 1996. - */ -int -Curl_inet_pton(int af, const char *src, void *dst) -{ - switch (af) { - case AF_INET: - return (inet_pton4(src, (unsigned char *)dst)); -#ifdef ENABLE_IPV6 -#ifndef AF_INET6 -#define AF_INET6 (AF_MAX+1) /* just to let this compile */ -#endif - case AF_INET6: - return (inet_pton6(src, (unsigned char *)dst)); -#endif - default: - errno = EAFNOSUPPORT; - return (-1); - } - /* NOTREACHED */ -} - -/* int - * inet_pton4(src, dst) - * like inet_aton() but without all the hexadecimal and shorthand. - * return: - * 1 if `src' is a valid dotted quad, else 0. - * notice: - * does not touch `dst' unless it's returning 1. - * author: - * Paul Vixie, 1996. - */ -static int -inet_pton4(const char *src, unsigned char *dst) -{ - static const char digits[] = "0123456789"; - int saw_digit, octets, ch; - unsigned char tmp[INADDRSZ], *tp; - - saw_digit = 0; - octets = 0; - tp = tmp; - *tp = 0; - while ((ch = *src++) != '\0') { - const char *pch; - - if ((pch = strchr(digits, ch)) != NULL) { - unsigned int val = *tp * 10 + (unsigned int)(pch - digits); - - if (val > 255) - return (0); - *tp = val; - if (! saw_digit) { - if (++octets > 4) - return (0); - saw_digit = 1; - } - } else if (ch == '.' && saw_digit) { - if (octets == 4) - return (0); - *++tp = 0; - saw_digit = 0; - } else - return (0); - } - if (octets < 4) - return (0); - /* bcopy(tmp, dst, INADDRSZ); */ - memcpy(dst, tmp, INADDRSZ); - return (1); -} - -#ifdef ENABLE_IPV6 -/* int - * inet_pton6(src, dst) - * convert presentation level address to network order binary form. - * return: - * 1 if `src' is a valid [RFC1884 2.2] address, else 0. - * notice: - * (1) does not touch `dst' unless it's returning 1. - * (2) :: in a full address is silently ignored. - * credit: - * inspired by Mark Andrews. - * author: - * Paul Vixie, 1996. - */ -static int -inet_pton6(const char *src, unsigned char *dst) -{ - static const char xdigits_l[] = "0123456789abcdef", - xdigits_u[] = "0123456789ABCDEF"; - unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; - const char *xdigits, *curtok; - int ch, saw_xdigit; - unsigned int val; - - memset((tp = tmp), 0, IN6ADDRSZ); - endp = tp + IN6ADDRSZ; - colonp = NULL; - /* Leading :: requires some special handling. */ - if (*src == ':') - if (*++src != ':') - return (0); - curtok = src; - saw_xdigit = 0; - val = 0; - while ((ch = *src++) != '\0') { - const char *pch; - - if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) - pch = strchr((xdigits = xdigits_u), ch); - if (pch != NULL) { - val <<= 4; - val |= (pch - xdigits); - if (val > 0xffff) - return (0); - saw_xdigit = 1; - continue; - } - if (ch == ':') { - curtok = src; - if (!saw_xdigit) { - if (colonp) - return (0); - colonp = tp; - continue; - } - if (tp + INT16SZ > endp) - return (0); - *tp++ = (unsigned char) (val >> 8) & 0xff; - *tp++ = (unsigned char) val & 0xff; - saw_xdigit = 0; - val = 0; - continue; - } - if (ch == '.' && ((tp + INADDRSZ) <= endp) && - inet_pton4(curtok, tp) > 0) { - tp += INADDRSZ; - saw_xdigit = 0; - break; /* '\0' was seen by inet_pton4(). */ - } - return (0); - } - if (saw_xdigit) { - if (tp + INT16SZ > endp) - return (0); - *tp++ = (unsigned char) (val >> 8) & 0xff; - *tp++ = (unsigned char) val & 0xff; - } - if (colonp != NULL) { - /* - * Since some memmove()'s erroneously fail to handle - * overlapping regions, we'll do the shift by hand. - */ - const int n = tp - colonp; - int i; - - for (i = 1; i <= n; i++) { - endp[- i] = colonp[n - i]; - colonp[n - i] = 0; - } - tp = endp; - } - if (tp != endp) - return (0); - /* bcopy(tmp, dst, IN6ADDRSZ); */ - memcpy(dst, tmp, IN6ADDRSZ); - return (1); -} -#endif /* ENABLE_IPV6 */ - -#endif /* HAVE_INET_PTON */ diff --git a/Utilities/cmcurl/inet_pton.h b/Utilities/cmcurl/inet_pton.h deleted file mode 100644 index a659a97..0000000 --- a/Utilities/cmcurl/inet_pton.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __INET_PTON_H -#define __INET_PTON_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -int Curl_inet_pton(int, const char *, void *); - -#ifdef HAVE_INET_PTON - -#if defined(HAVE_NO_INET_PTON_PROTO) -int inet_pton(int af, const char *src, void *dst); -#endif - -#ifdef HAVE_ARPA_INET_H -#include -#endif -#define Curl_inet_pton(x,y,z) inet_pton(x,y,z) -#endif - -#endif /* __INET_PTON_H */ diff --git a/Utilities/cmcurl/krb4.c b/Utilities/cmcurl/krb4.c deleted file mode 100644 index f2b91df..0000000 --- a/Utilities/cmcurl/krb4.c +++ /dev/null @@ -1,425 +0,0 @@ -/* This source code was modified by Martin Hedenfalk for - * use in Curl. Martin's latest changes were done 2000-09-18. - * - * It has since been patched away like a madman by Daniel Stenberg to make it - * better applied to curl conditions, and to make it not use globals, pollute - * name space and more. - * - * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (c) 2004 - 2007 Daniel Stenberg - * All rights reserved. - * - * 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. - * - * $Id$ - */ - -#include "setup.h" - -#ifndef CURL_DISABLE_FTP -#ifdef HAVE_KRB4 - -#include -#ifdef HAVE_NETDB_H -#include -#endif -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include /* for getpid() */ -#endif - -#include "urldata.h" -#include "base64.h" -#include "ftp.h" -#include "sendf.h" -#include "krb4.h" -#include "memory.h" - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -/* The last #include file should be: */ -#include "memdebug.h" - -#define LOCAL_ADDR (&conn->local_addr) -#define REMOTE_ADDR conn->ip_addr->ai_addr -#define myctladdr LOCAL_ADDR -#define hisctladdr REMOTE_ADDR - -struct krb4_data { - des_cblock key; - des_key_schedule schedule; - char name[ANAME_SZ]; - char instance[INST_SZ]; - char realm[REALM_SZ]; -}; - -#ifndef HAVE_STRLCPY -/* if it ever goes non-static, make it Curl_ prefixed! */ -static size_t -strlcpy (char *dst, const char *src, size_t dst_sz) -{ - size_t n; - char *p; - - for (p = dst, n = 0; - n + 1 < dst_sz && *src != '\0'; - ++p, ++src, ++n) - *p = *src; - *p = '\0'; - if (*src == '\0') - return n; - else - return n + strlen (src); -} -#else -size_t strlcpy (char *dst, const char *src, size_t dst_sz); -#endif - -static int -krb4_check_prot(void *app_data, int level) -{ - app_data = NULL; /* prevent compiler warning */ - if(level == prot_confidential) - return -1; - return 0; -} - -static int -krb4_decode(void *app_data, void *buf, int len, int level, - struct connectdata *conn) -{ - MSG_DAT m; - int e; - struct krb4_data *d = app_data; - - if(level == prot_safe) - e = krb_rd_safe(buf, len, &d->key, - (struct sockaddr_in *)REMOTE_ADDR, - (struct sockaddr_in *)LOCAL_ADDR, &m); - else - e = krb_rd_priv(buf, len, d->schedule, &d->key, - (struct sockaddr_in *)REMOTE_ADDR, - (struct sockaddr_in *)LOCAL_ADDR, &m); - if(e) { - struct SessionHandle *data = conn->data; - infof(data, "krb4_decode: %s\n", krb_get_err_text(e)); - return -1; - } - memmove(buf, m.app_data, m.app_length); - return m.app_length; -} - -static int -krb4_overhead(void *app_data, int level, int len) -{ - /* no arguments are used, just init them to prevent compiler warnings */ - app_data = NULL; - level = 0; - len = 0; - return 31; -} - -static int -krb4_encode(void *app_data, void *from, int length, int level, void **to, - struct connectdata *conn) -{ - struct krb4_data *d = app_data; - *to = malloc(length + 31); - if(level == prot_safe) - return krb_mk_safe(from, *to, length, &d->key, - (struct sockaddr_in *)LOCAL_ADDR, - (struct sockaddr_in *)REMOTE_ADDR); - else if(level == prot_private) - return krb_mk_priv(from, *to, length, d->schedule, &d->key, - (struct sockaddr_in *)LOCAL_ADDR, - (struct sockaddr_in *)REMOTE_ADDR); - else - return -1; -} - -static int -mk_auth(struct krb4_data *d, KTEXT adat, - const char *service, char *host, int checksum) -{ - int ret; - CREDENTIALS cred; - char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ]; - - strlcpy(sname, service, sizeof(sname)); - strlcpy(inst, krb_get_phost(host), sizeof(inst)); - strlcpy(realm, krb_realmofhost(host), sizeof(realm)); - ret = krb_mk_req(adat, sname, inst, realm, checksum); - if(ret) - return ret; - strlcpy(sname, service, sizeof(sname)); - strlcpy(inst, krb_get_phost(host), sizeof(inst)); - strlcpy(realm, krb_realmofhost(host), sizeof(realm)); - ret = krb_get_cred(sname, inst, realm, &cred); - memmove(&d->key, &cred.session, sizeof(des_cblock)); - des_key_sched(&d->key, d->schedule); - memset(&cred, 0, sizeof(cred)); - return ret; -} - -#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM -int krb_get_our_ip_for_realm(char *, struct in_addr *); -#endif - -static int -krb4_auth(void *app_data, struct connectdata *conn) -{ - int ret; - char *p; - unsigned char *ptr; - size_t len; - KTEXT_ST adat; - MSG_DAT msg_data; - int checksum; - u_int32_t cs; - struct krb4_data *d = app_data; - char *host = conn->host.name; - ssize_t nread; - int l = sizeof(conn->local_addr); - struct SessionHandle *data = conn->data; - CURLcode result; - - if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)LOCAL_ADDR, &l) < 0) - perror("getsockname()"); - - checksum = getpid(); - ret = mk_auth(d, &adat, "ftp", host, checksum); - if(ret == KDC_PR_UNKNOWN) - ret = mk_auth(d, &adat, "rcmd", host, checksum); - if(ret) { - infof(data, "%s\n", krb_get_err_text(ret)); - return AUTH_CONTINUE; - } - -#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM - if (krb_get_config_bool("nat_in_use")) { - struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR; - struct in_addr natAddr; - - if (krb_get_our_ip_for_realm(krb_realmofhost(host), - &natAddr) != KSUCCESS - && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS) - infof(data, "Can't get address for realm %s\n", - krb_realmofhost(host)); - else { - if (natAddr.s_addr != localaddr->sin_addr.s_addr) { -#ifdef HAVE_INET_NTOA_R - char ntoa_buf[64]; - char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf)); -#else - char *ip = (char *)inet_ntoa(natAddr); -#endif - infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip); - localaddr->sin_addr = natAddr; - } - } - } -#endif - - if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) { - Curl_failf(data, "Out of memory base64-encoding"); - return AUTH_CONTINUE; - } - - result = Curl_ftpsendf(conn, "ADAT %s", p); - - free(p); - - if(result) - return -2; - - if(Curl_GetFTPResponse(&nread, conn, NULL)) - return -1; - - if(data->state.buffer[0] != '2'){ - Curl_failf(data, "Server didn't accept auth data"); - return AUTH_ERROR; - } - - p = strstr(data->state.buffer, "ADAT="); - if(!p) { - Curl_failf(data, "Remote host didn't send adat reply"); - return AUTH_ERROR; - } - p += 5; - len = Curl_base64_decode(p, &ptr); - if(len > sizeof(adat.dat)-1) { - free(ptr); - len=0; - } - if(!len || !ptr) { - Curl_failf(data, "Failed to decode base64 from server"); - return AUTH_ERROR; - } - memcpy((char *)adat.dat, ptr, len); - free(ptr); - adat.length = len; - ret = krb_rd_safe(adat.dat, adat.length, &d->key, - (struct sockaddr_in *)hisctladdr, - (struct sockaddr_in *)myctladdr, &msg_data); - if(ret) { - Curl_failf(data, "Error reading reply from server: %s", - krb_get_err_text(ret)); - return AUTH_ERROR; - } - krb_get_int(msg_data.app_data, &cs, 4, 0); - if(cs - checksum != 1) { - Curl_failf(data, "Bad checksum returned from server"); - return AUTH_ERROR; - } - return AUTH_OK; -} - -struct Curl_sec_client_mech Curl_krb4_client_mech = { - "KERBEROS_V4", - sizeof(struct krb4_data), - NULL, /* init */ - krb4_auth, - NULL, /* end */ - krb4_check_prot, - krb4_overhead, - krb4_encode, - krb4_decode -}; - -CURLcode Curl_krb_kauth(struct connectdata *conn) -{ - des_cblock key; - des_key_schedule schedule; - KTEXT_ST tkt, tktcopy; - char *name; - char *p; - char passwd[100]; - size_t tmp; - ssize_t nread; - int save; - CURLcode result; - unsigned char *ptr; - - save = Curl_set_command_prot(conn, prot_private); - - result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user); - - if(result) - return result; - - result = Curl_GetFTPResponse(&nread, conn, NULL); - if(result) - return result; - - if(conn->data->state.buffer[0] != '3'){ - Curl_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - p = strstr(conn->data->state.buffer, "T="); - if(!p) { - Curl_failf(conn->data, "Bad reply from server"); - Curl_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - p += 2; - tmp = Curl_base64_decode(p, &ptr); - if(tmp >= sizeof(tkt.dat)) { - free(ptr); - tmp=0; - } - if(!tmp || !ptr) { - Curl_failf(conn->data, "Failed to decode base64 in reply.\n"); - Curl_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - memcpy((char *)tkt.dat, ptr, tmp); - free(ptr); - tkt.length = tmp; - tktcopy.length = tkt.length; - - p = strstr(conn->data->state.buffer, "P="); - if(!p) { - Curl_failf(conn->data, "Bad reply from server"); - Curl_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - name = p + 2; - for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++); - *p = 0; - - des_string_to_key (conn->passwd, &key); - des_key_sched(&key, schedule); - - des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat, - tkt.length, - schedule, &key, DES_DECRYPT); - if (strcmp ((char*)tktcopy.dat + 8, - KRB_TICKET_GRANTING_TICKET) != 0) { - afs_string_to_key(passwd, - krb_realmofhost(conn->host.name), - &key); - des_key_sched(&key, schedule); - des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat, - tkt.length, - schedule, &key, DES_DECRYPT); - } - memset(key, 0, sizeof(key)); - memset(schedule, 0, sizeof(schedule)); - memset(passwd, 0, sizeof(passwd)); - if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p) - < 1) { - failf(conn->data, "Out of memory base64-encoding."); - Curl_set_command_prot(conn, save); - return CURLE_OUT_OF_MEMORY; - } - memset (tktcopy.dat, 0, tktcopy.length); - - result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p); - free(p); - if(result) - return result; - - result = Curl_GetFTPResponse(&nread, conn, NULL); - if(result) - return result; - Curl_set_command_prot(conn, save); - - return CURLE_OK; -} - -#endif /* HAVE_KRB4 */ -#endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/krb4.h b/Utilities/cmcurl/krb4.h deleted file mode 100644 index f46416e..0000000 --- a/Utilities/cmcurl/krb4.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef __KRB4_H -#define __KRB4_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -struct Curl_sec_client_mech { - const char *name; - size_t size; - int (*init)(void *); - int (*auth)(void *, struct connectdata *); - void (*end)(void *); - int (*check_prot)(void *, int); - int (*overhead)(void *, int, int); - int (*encode)(void *, void*, int, int, void**, struct connectdata *); - int (*decode)(void *, void*, int, int, struct connectdata *); -}; - - -#define AUTH_OK 0 -#define AUTH_CONTINUE 1 -#define AUTH_ERROR 2 - -extern struct Curl_sec_client_mech Curl_krb4_client_mech; - -CURLcode Curl_krb_kauth(struct connectdata *conn); -int Curl_sec_fflush_fd(struct connectdata *conn, int fd); -int Curl_sec_fprintf (struct connectdata *, FILE *, const char *, ...); -int Curl_sec_getc (struct connectdata *conn, FILE *); -int Curl_sec_putc (struct connectdata *conn, int, FILE *); -int Curl_sec_read (struct connectdata *conn, int, void *, int); -int Curl_sec_read_msg (struct connectdata *conn, char *, int); - -int Curl_sec_vfprintf(struct connectdata *, FILE *, const char *, va_list); -int Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...); -int Curl_sec_vfprintf2(struct connectdata *conn, FILE *, const char *, va_list); -ssize_t Curl_sec_send(struct connectdata *conn, int, char *, int); -int Curl_sec_write(struct connectdata *conn, int, char *, int); - -void Curl_sec_end (struct connectdata *); -int Curl_sec_login (struct connectdata *); -void Curl_sec_prot (int, char **); -int Curl_sec_request_prot (struct connectdata *conn, const char *level); -void Curl_sec_set_protection_level(struct connectdata *conn); -void Curl_sec_status (void); - -enum protection_level Curl_set_command_prot(struct connectdata *, - enum protection_level); - - -#endif diff --git a/Utilities/cmcurl/ldap.c b/Utilities/cmcurl/ldap.c deleted file mode 100644 index 3e1144d..0000000 --- a/Utilities/cmcurl/ldap.c +++ /dev/null @@ -1,702 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_LDAP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef NEED_MALLOC_H -#include -#endif -#include - -#if defined(WIN32) -# include -#endif - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifdef HAVE_DLFCN_H -# include -#endif - -#include "urldata.h" -#include -#include "sendf.h" -#include "escape.h" -#include "transfer.h" -#include "strequal.h" -#include "strtok.h" -#include "ldap.h" -#include "memory.h" -#include "base64.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "memdebug.h" - -/* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl - * pointers in case libcurl was compiled as fastcall (cl -Gr). Watcom - * uses fastcall by default. - */ -#if !defined(WIN32) && !defined(__cdecl) -#define __cdecl -#endif - -#ifndef LDAP_SIZELIMIT_EXCEEDED -#define LDAP_SIZELIMIT_EXCEEDED 4 -#endif -#ifndef LDAP_VERSION2 -#define LDAP_VERSION2 2 -#endif -#ifndef LDAP_VERSION3 -#define LDAP_VERSION3 3 -#endif -#ifndef LDAP_OPT_PROTOCOL_VERSION -#define LDAP_OPT_PROTOCOL_VERSION 0x0011 -#endif - -#define DLOPEN_MODE RTLD_LAZY /*! assume all dlopen() implementations have - this */ - -#if defined(RTLD_LAZY_GLOBAL) /* It turns out some systems use this: */ -# undef DLOPEN_MODE -# define DLOPEN_MODE RTLD_LAZY_GLOBAL -#elif defined(RTLD_GLOBAL) -# undef DLOPEN_MODE -# define DLOPEN_MODE (RTLD_LAZY | RTLD_GLOBAL) -#endif - -#define DYNA_GET_FUNCTION(type, fnc) do { \ - (fnc) = (type)DynaGetFunction(#fnc); \ - if ((fnc) == NULL) \ - return CURLE_FUNCTION_NOT_FOUND; \ - } while (0) - -/*! CygWin etc. configure could set these, but we don't want it. - * Must use WLdap32.dll code. - */ -#if defined(WIN32) -#undef HAVE_DLOPEN -#undef HAVE_LIBDL -#endif - -/* - * We use this ZERO_NULL to avoid picky compiler warnings, - * when assigning a NULL pointer to a function pointer var. - */ - -#define ZERO_NULL 0 - -typedef void * (*dynafunc)(void *input); - -/*********************************************************************** - */ -#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) || defined(WIN32) -static void *libldap = NULL; -#if defined(DL_LBER_FILE) -static void *liblber = NULL; -#endif -#endif - -struct bv { - unsigned long bv_len; - char *bv_val; -}; - -static int DynaOpen(const char **mod_name) -{ -#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) - if (libldap == NULL) { - /* - * libldap.so can normally resolve its dependency on liblber.so - * automatically, but in broken installation it does not so - * handle it here by opening liblber.so as global. - */ -#ifdef DL_LBER_FILE - *mod_name = DL_LBER_FILE; - liblber = dlopen(*mod_name, DLOPEN_MODE); - if (!liblber) - return 0; -#endif - - /* Assume loading libldap.so will fail if loading of liblber.so failed - */ - *mod_name = DL_LDAP_FILE; - libldap = dlopen(*mod_name, RTLD_LAZY); - } - return (libldap != NULL); - -#elif defined(WIN32) - *mod_name = DL_LDAP_FILE; - if (!libldap) - libldap = (void*)LoadLibrary(*mod_name); - return (libldap != NULL); - -#else - *mod_name = ""; - return (0); -#endif -} - -static void DynaClose(void) -{ -#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) - if (libldap) { - dlclose(libldap); - libldap=NULL; - } -#ifdef DL_LBER_FILE - if (liblber) { - dlclose(liblber); - liblber=NULL; - } -#endif -#elif defined(WIN32) - if (libldap) { - FreeLibrary ((HMODULE)libldap); - libldap = NULL; - } -#endif -} - -static dynafunc DynaGetFunction(const char *name) -{ - dynafunc func = (dynafunc)ZERO_NULL; - -#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) - if (libldap) { - /* This typecast magic below was brought by Joe Halpin. In ISO C, you - * cannot typecast a data pointer to a function pointer, but that's - * exactly what we need to do here to avoid compiler warnings on picky - * compilers! */ - *(void**) (&func) = dlsym(libldap, name); - } -#elif defined(WIN32) - if (libldap) { - func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name); - } -#else - (void) name; -#endif - return func; -} - -/*********************************************************************** - */ -typedef struct ldap_url_desc { - struct ldap_url_desc *lud_next; - char *lud_scheme; - char *lud_host; - int lud_port; - char *lud_dn; - char **lud_attrs; - int lud_scope; - char *lud_filter; - char **lud_exts; - int lud_crit_exts; -} LDAPURLDesc; - -#ifdef WIN32 -static int _ldap_url_parse (const struct connectdata *conn, - LDAPURLDesc **ludp); -static void _ldap_free_urldesc (LDAPURLDesc *ludp); - -static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc; -#endif - -#ifdef DEBUG_LDAP - #define LDAP_TRACE(x) do { \ - _ldap_trace ("%u: ", __LINE__); \ - _ldap_trace x; \ - } while (0) - - static void _ldap_trace (const char *fmt, ...); -#else - #define LDAP_TRACE(x) ((void)0) -#endif - - -CURLcode Curl_ldap(struct connectdata *conn, bool *done) -{ - CURLcode status = CURLE_OK; - int rc = 0; -#ifndef WIN32 - int (*ldap_url_parse)(char *, LDAPURLDesc **); - void (*ldap_free_urldesc)(void *); -#endif - void *(__cdecl *ldap_init)(char *, int); - int (__cdecl *ldap_simple_bind_s)(void *, char *, char *); - int (__cdecl *ldap_unbind_s)(void *); - int (__cdecl *ldap_search_s)(void *, char *, int, char *, char **, - int, void **); - void *(__cdecl *ldap_first_entry)(void *, void *); - void *(__cdecl *ldap_next_entry)(void *, void *); - char *(__cdecl *ldap_err2string)(int); - char *(__cdecl *ldap_get_dn)(void *, void *); - char *(__cdecl *ldap_first_attribute)(void *, void *, void **); - char *(__cdecl *ldap_next_attribute)(void *, void *, void *); - void **(__cdecl *ldap_get_values_len)(void *, void *, const char *); - void (__cdecl *ldap_value_free_len)(void **); - void (__cdecl *ldap_memfree)(void *); - void (__cdecl *ber_free)(void *, int); - int (__cdecl *ldap_set_option)(void *, int, void *); - - void *server; - LDAPURLDesc *ludp = NULL; - const char *mod_name; - void *result; - void *entryIterator; /*! type should be 'LDAPMessage *' */ - int num = 0; - struct SessionHandle *data=conn->data; - int ldap_proto; - char *val_b64; - size_t val_b64_sz; - - *done = TRUE; /* unconditionally */ - infof(data, "LDAP local: %s\n", data->change.url); - - if (!DynaOpen(&mod_name)) { - failf(data, "The %s LDAP library/libraries couldn't be opened", mod_name); - return CURLE_LIBRARY_NOT_FOUND; - } - - /* The types are needed because ANSI C distinguishes between - * pointer-to-object (data) and pointer-to-function. - */ - DYNA_GET_FUNCTION(void *(__cdecl *)(char *, int), ldap_init); - DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, char *), - ldap_simple_bind_s); - DYNA_GET_FUNCTION(int (__cdecl *)(void *), ldap_unbind_s); -#ifndef WIN32 - DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse); - DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc); -#endif - DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, int, char *, char **, int, - void **), ldap_search_s); - DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_first_entry); - DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_next_entry); - DYNA_GET_FUNCTION(char *(__cdecl *)(int), ldap_err2string); - DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *), ldap_get_dn); - DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void **), - ldap_first_attribute); - DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void *), - ldap_next_attribute); - DYNA_GET_FUNCTION(void **(__cdecl *)(void *, void *, const char *), - ldap_get_values_len); - DYNA_GET_FUNCTION(void (__cdecl *)(void **), ldap_value_free_len); - DYNA_GET_FUNCTION(void (__cdecl *)(void *), ldap_memfree); - DYNA_GET_FUNCTION(void (__cdecl *)(void *, int), ber_free); - DYNA_GET_FUNCTION(int (__cdecl *)(void *, int, void *), ldap_set_option); - - server = (*ldap_init)(conn->host.name, (int)conn->port); - if (server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%d", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; - goto quit; - } - - ldap_proto = LDAP_VERSION3; - (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); - rc = (*ldap_simple_bind_s)(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); - if (rc != 0) { - ldap_proto = LDAP_VERSION2; - (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); - rc = (*ldap_simple_bind_s)(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); - } - if (rc != 0) { - failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); - status = CURLE_LDAP_CANNOT_BIND; - goto quit; - } - -#ifdef WIN32 - rc = _ldap_url_parse(conn, &ludp); -#else - rc = (*ldap_url_parse)(data->change.url, &ludp); -#endif - - if (rc != 0) { - failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); - status = CURLE_LDAP_INVALID_URL; - goto quit; - } - - rc = (*ldap_search_s)(server, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, &result); - - if (rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { - failf(data, "LDAP remote: %s", (*ldap_err2string)(rc)); - status = CURLE_LDAP_SEARCH_FAILED; - goto quit; - } - - for(num = 0, entryIterator = (*ldap_first_entry)(server, result); - entryIterator; - entryIterator = (*ldap_next_entry)(server, entryIterator), num++) - { - void *ber = NULL; /*! is really 'BerElement **' */ - void *attribute; /*! suspicious that this isn't 'const' */ - char *dn = (*ldap_get_dn)(server, entryIterator); - int i; - - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - - for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber); - attribute; - attribute = (*ldap_next_attribute)(server, entryIterator, ber)) - { - struct bv **vals = (struct bv **) - (*ldap_get_values_len)(server, entryIterator, attribute); - - if (vals != NULL) - { - for (i = 0; (vals[i] != NULL); i++) - { - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); - if ((strlen(attribute) > 7) && - (strcmp(";binary", - (char *)attribute + - (strlen((char *)attribute) - 7)) == 0)) { - /* Binary attribute, encode to base64. */ - val_b64_sz = Curl_base64_encode(conn->data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64); - if (val_b64_sz > 0) { - Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); - free(val_b64); - } - } else - Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, - vals[i]->bv_len); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); - } - - /* Free memory used to store values */ - (*ldap_value_free_len)((void **)vals); - } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - - (*ldap_memfree)(attribute); - } - (*ldap_memfree)(dn); - if (ber) - (*ber_free)(ber, 0); - } - -quit: - LDAP_TRACE (("Received %d entries\n", num)); - if (rc == LDAP_SIZELIMIT_EXCEEDED) - infof(data, "There are more than %d entries\n", num); - if (ludp) - (*ldap_free_urldesc)(ludp); - if (server) - (*ldap_unbind_s)(server); - - DynaClose(); - - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - conn->bits.close = TRUE; - - return status; -} - -#ifdef DEBUG_LDAP -static void _ldap_trace (const char *fmt, ...) -{ - static int do_trace = -1; - va_list args; - - if (do_trace == -1) { - const char *env = getenv("CURL_TRACE"); - do_trace = (env && atoi(env) > 0); - } - if (!do_trace) - return; - - va_start (args, fmt); - vfprintf (stderr, fmt, args); - va_end (args); -} -#endif - -#ifdef WIN32 -/* - * Return scope-value for a scope-string. - */ -static int str2scope (const char *p) -{ - if (!stricmp(p, "one")) - return LDAP_SCOPE_ONELEVEL; - if (!stricmp(p, "onetree")) - return LDAP_SCOPE_ONELEVEL; - if (!stricmp(p, "base")) - return LDAP_SCOPE_BASE; - if (!stricmp(p, "sub")) - return LDAP_SCOPE_SUBTREE; - if (!stricmp( p, "subtree")) - return LDAP_SCOPE_SUBTREE; - return (-1); -} - -/* - * Split 'str' into strings separated by commas. - * Note: res[] points into 'str'. - */ -static char **split_str (char *str) -{ - char **res, *lasts, *s; - int i; - - for (i = 2, s = strchr(str,','); s; i++) - s = strchr(++s,','); - - res = calloc(i, sizeof(char*)); - if (!res) - return NULL; - - for (i = 0, s = strtok_r(str, ",", &lasts); s; - s = strtok_r(NULL, ",", &lasts), i++) - res[i] = s; - return res; -} - -/* - * Unescape the LDAP-URL components - */ -static bool unescape_elements (void *data, LDAPURLDesc *ludp) -{ - int i; - - if (ludp->lud_filter) { - ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL); - if (!ludp->lud_filter) - return (FALSE); - } - - for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { - ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL); - if (!ludp->lud_attrs[i]) - return (FALSE); - } - - for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) { - ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL); - if (!ludp->lud_exts[i]) - return (FALSE); - } - - if (ludp->lud_dn) { - char *dn = ludp->lud_dn; - char *new_dn = curl_easy_unescape(data, dn, 0, NULL); - - free(dn); - ludp->lud_dn = new_dn; - if (!new_dn) - return (FALSE); - } - return (TRUE); -} - -/* - * Break apart the pieces of an LDAP URL. - * Syntax: - * ldap://:/???? - * - * already known from 'conn->host.name'. - * already known from 'conn->remote_port'. - * extract the rest from 'conn->data->reqdata.path+1'. All fields are optional. - * e.g. - * ldap://:/??? - * yields ludp->lud_dn = "". - * - * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915 - */ -static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) -{ - char *p, *q; - int i; - - if (!conn->data || - !conn->data->reqdata.path || - conn->data->reqdata.path[0] != '/' || - !checkprefix(conn->protostr, conn->data->change.url)) - return LDAP_INVALID_SYNTAX; - - ludp->lud_scope = LDAP_SCOPE_BASE; - ludp->lud_port = conn->remote_port; - ludp->lud_host = conn->host.name; - - /* parse DN (Distinguished Name). - */ - ludp->lud_dn = strdup(conn->data->reqdata.path+1); - if (!ludp->lud_dn) - return LDAP_NO_MEMORY; - - p = strchr(ludp->lud_dn, '?'); - LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : - strlen(ludp->lud_dn), ludp->lud_dn)); - - if (!p) - goto success; - - *p++ = '\0'; - - /* parse attributes. skip "??". - */ - q = strchr(p, '?'); - if (q) - *q++ = '\0'; - - if (*p && *p != '?') { - ludp->lud_attrs = split_str(p); - if (!ludp->lud_attrs) - return LDAP_NO_MEMORY; - - for (i = 0; ludp->lud_attrs[i]; i++) - LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); - } - - p = q; - if (!p) - goto success; - - /* parse scope. skip "??" - */ - q = strchr(p, '?'); - if (q) - *q++ = '\0'; - - if (*p && *p != '?') { - ludp->lud_scope = str2scope(p); - if (ludp->lud_scope == -1) - return LDAP_INVALID_SYNTAX; - LDAP_TRACE (("scope %d\n", ludp->lud_scope)); - } - - p = q; - if (!p) - goto success; - - /* parse filter - */ - q = strchr(p, '?'); - if (q) - *q++ = '\0'; - if (!*p) - return LDAP_INVALID_SYNTAX; - - ludp->lud_filter = p; - LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); - - p = q; - if (!p) - goto success; - - /* parse extensions - */ - ludp->lud_exts = split_str(p); - if (!ludp->lud_exts) - return LDAP_NO_MEMORY; - - for (i = 0; ludp->lud_exts[i]; i++) - LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i])); - -success: - if (!unescape_elements(conn->data, ludp)) - return LDAP_NO_MEMORY; - return LDAP_SUCCESS; -} - -static int _ldap_url_parse (const struct connectdata *conn, - LDAPURLDesc **ludpp) -{ - LDAPURLDesc *ludp = calloc(sizeof(*ludp), 1); - int rc; - - *ludpp = NULL; - if (!ludp) - return LDAP_NO_MEMORY; - - rc = _ldap_url_parse2 (conn, ludp); - if (rc != LDAP_SUCCESS) { - _ldap_free_urldesc(ludp); - ludp = NULL; - } - *ludpp = ludp; - return (rc); -} - -static void _ldap_free_urldesc (LDAPURLDesc *ludp) -{ - int i; - - if (!ludp) - return; - - if (ludp->lud_dn) - free(ludp->lud_dn); - - if (ludp->lud_filter) - free(ludp->lud_filter); - - if (ludp->lud_attrs) { - for (i = 0; ludp->lud_attrs[i]; i++) - free(ludp->lud_attrs[i]); - free(ludp->lud_attrs); - } - - if (ludp->lud_exts) { - for (i = 0; ludp->lud_exts[i]; i++) - free(ludp->lud_exts[i]); - free(ludp->lud_exts); - } - free (ludp); -} -#endif /* WIN32 */ -#endif /* CURL_DISABLE_LDAP */ diff --git a/Utilities/cmcurl/ldap.h b/Utilities/cmcurl/ldap.h deleted file mode 100644 index b2d4f39..0000000 --- a/Utilities/cmcurl/ldap.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __LDAP_H -#define __LDAP_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_LDAP -CURLcode Curl_ldap(struct connectdata *conn, bool *done); -#endif -#endif /* __LDAP_H */ diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c new file mode 100644 index 0000000..7106f8d --- /dev/null +++ b/Utilities/cmcurl/lib/amigaos.c @@ -0,0 +1,74 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "amigaos.h" +#include + +struct Library *SocketBase = NULL; +extern int errno, h_errno; + +#ifdef __libnix__ +#include +void __request(const char *msg); +#else +# define __request( msg ) Printf( msg "\n\a") +#endif + +void amiga_cleanup() +{ + if(SocketBase) { + CloseLibrary(SocketBase); + SocketBase = NULL; + } +} + +BOOL amiga_init() +{ + if(!SocketBase) + SocketBase = OpenLibrary("bsdsocket.library", 4); + + if(!SocketBase) { + __request("No TCP/IP Stack running!"); + return FALSE; + } + + if(SocketBaseTags( + SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, +// SBTM_SETVAL(SBTC_HERRNOLONGPTR), (ULONG) &h_errno, + SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL", + TAG_DONE)) { + + __request("SocketBaseTags ERROR"); + return FALSE; + } + +#ifndef __libnix__ + atexit(amiga_cleanup); +#endif + + return TRUE; +} + +#ifdef __libnix__ +ADD2EXIT(amiga_cleanup,-50); +#endif diff --git a/Utilities/cmcurl/lib/amigaos.h b/Utilities/cmcurl/lib/amigaos.h new file mode 100644 index 0000000..e5786d4 --- /dev/null +++ b/Utilities/cmcurl/lib/amigaos.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifndef LIBCURL_AMIGAOS_H +#define LIBCURL_AMIGAOS_H + +#ifndef __ixemul__ + +#include +#include + +#include +#include + +#include + +#include "config-amigaos.h" + +#ifndef select +# define select(args...) WaitSelect( args, NULL) +#endif +#ifndef inet_ntoa +# define inet_ntoa(x) Inet_NtoA( x ## .s_addr) +#endif +#ifndef ioctl +# define ioctl(a,b,c,d) IoctlSocket( (LONG)a, (ULONG)b, (char*)c) +#endif +#define _AMIGASF 1 + +extern void amiga_cleanup(); +extern BOOL amiga_init(); + +#else /* __ixemul__ */ + +#warning compiling with ixemul... + +#endif /* __ixemul__ */ +#endif /* LIBCURL_AMIGAOS_H */ diff --git a/Utilities/cmcurl/lib/arpa_telnet.h b/Utilities/cmcurl/lib/arpa_telnet.h new file mode 100644 index 0000000..e6a04dc --- /dev/null +++ b/Utilities/cmcurl/lib/arpa_telnet.h @@ -0,0 +1,101 @@ +#ifndef __ARPA_TELNET_H +#define __ARPA_TELNET_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_TELNET +/* + * Telnet option defines. Add more here if in need. + */ +#define CURL_TELOPT_BINARY 0 /* binary 8bit data */ +#define CURL_TELOPT_SGA 3 /* Supress Go Ahead */ +#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ +#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ +#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ + +#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */ +#define CURL_NEW_ENV_VAR 0 +#define CURL_NEW_ENV_VALUE 1 + +/* + * The telnet options represented as strings + */ +static const char * const telnetoptions[]= +{ + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", + "NAME", "STATUS", "TIMING MARK", "RCTE", + "NAOL", "NAOP", "NAOCRD", "NAOHTS", + "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", + "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", + "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", + "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS", + "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC", + "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON" +}; + +#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON + +#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM) +#define CURL_TELOPT(x) telnetoptions[x] + +#define CURL_NTELOPTS 40 + +/* + * First some defines + */ +#define CURL_xEOF 236 /* End Of File */ +#define CURL_SE 240 /* Sub negotiation End */ +#define CURL_NOP 241 /* No OPeration */ +#define CURL_DM 242 /* Data Mark */ +#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 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 */ + +/* + * Then those numbers represented as strings: + */ +static const char * const telnetcmds[]= +{ + "EOF", "SUSP", "ABORT", "EOR", "SE", + "NOP", "DMARK", "BRK", "IP", "AO", + "AYT", "EC", "EL", "GA", "SB", + "WILL", "WONT", "DO", "DONT", "IAC" +}; + +#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */ +#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */ + +#define CURL_TELQUAL_IS 0 +#define CURL_TELQUAL_SEND 1 +#define CURL_TELQUAL_INFO 2 +#define CURL_TELQUAL_NAME 3 + +#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \ + ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) ) +#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM] +#endif +#endif diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c new file mode 100644 index 0000000..aa03f83 --- /dev/null +++ b/Utilities/cmcurl/lib/base64.c @@ -0,0 +1,366 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* Base64 encoding/decoding + * + * Test harnesses down the bottom - compile with -DTEST_ENCODE for + * a program that will read in raw data from stdin and write out + * a base64-encoded version to stdout, and the length returned by the + * encoding function to stderr. Compile with -DTEST_DECODE for a program that + * will go the other way. + * + * This code will break if int is smaller than 32 bits + */ + +#include "setup.h" + +#include +#include + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "urldata.h" /* for the SessionHandle definition */ +#include "easyif.h" /* for Curl_convert_... prototypes */ +#include "base64.h" +#include "memory.h" + +/* include memdebug.h last */ +#include "memdebug.h" + +/* ---- Base64 Encoding/Decoding Table --- */ +static const char table64[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void decodeQuantum(unsigned char *dest, const char *src) +{ + unsigned int x = 0; + int i; + char *found; + + for(i = 0; i < 4; i++) { + if((found = strchr(table64, src[i]))) + x = (x << 6) + (unsigned int)(found - table64); + else if(src[i] == '=') + x = (x << 6); + } + + dest[2] = (unsigned char)(x & 255); + x >>= 8; + dest[1] = (unsigned char)(x & 255); + x >>= 8; + dest[0] = (unsigned char)(x & 255); +} + +/* + * Curl_base64_decode() + * + * Given a base64 string at src, decode it and return an allocated memory in + * the *outptr. Returns the length of the decoded data. + */ +size_t Curl_base64_decode(const char *src, unsigned char **outptr) +{ + int length = 0; + int equalsTerm = 0; + int i; + int numQuantums; + unsigned char lastQuantum[3]; + size_t rawlen=0; + unsigned char *newstr; + + *outptr = NULL; + + while((src[length] != '=') && src[length]) + length++; + /* A maximum of two = padding characters is allowed */ + if(src[length] == '=') { + equalsTerm++; + if(src[length+equalsTerm] == '=') + equalsTerm++; + } + numQuantums = (length + equalsTerm) / 4; + + /* Don't allocate a buffer if the decoded length is 0 */ + if (numQuantums <= 0) + return 0; + + rawlen = (numQuantums * 3) - equalsTerm; + + /* The buffer must be large enough to make room for the last quantum + (which may be partially thrown out) and the zero terminator. */ + newstr = malloc(rawlen+4); + if(!newstr) + return 0; + + *outptr = newstr; + + /* Decode all but the last quantum (which may not decode to a + multiple of 3 bytes) */ + for(i = 0; i < numQuantums - 1; i++) { + decodeQuantum((unsigned char *)newstr, src); + newstr += 3; src += 4; + } + + /* This final decode may actually read slightly past the end of the buffer + if the input string is missing pad bytes. This will almost always be + harmless. */ + decodeQuantum(lastQuantum, src); + for(i = 0; i < 3 - equalsTerm; i++) + newstr[i] = lastQuantum[i]; + + newstr[i] = 0; /* zero terminate */ + return rawlen; +} + +/* + * Curl_base64_encode() + * + * Returns the length of the newly created base64 string. The third argument + * is a pointer to an allocated area holding the base64 data. If something + * went wrong, -1 is returned. + * + */ +size_t Curl_base64_encode(struct SessionHandle *data, + const char *inp, size_t insize, char **outptr) +{ + unsigned char ibuf[3]; + unsigned char obuf[4]; + int i; + int inputparts; + char *output; + char *base64data; +#ifdef CURL_DOES_CONVERSIONS + char *convbuf; +#endif + + char *indata = (char *)inp; + + *outptr = NULL; /* set to NULL in case of failure before we reach the end */ + + if(0 == insize) + insize = strlen(indata); + + base64data = output = (char*)malloc(insize*4/3+4); + if(NULL == output) + return 0; + +#ifdef CURL_DOES_CONVERSIONS + /* + * The base64 data needs to be created using the network encoding + * not the host encoding. And we can't change the actual input + * so we copy it to a buffer, translate it, and use that instead. + */ + if(data) { + convbuf = (char*)malloc(insize); + if(!convbuf) { + return 0; + } + memcpy(convbuf, indata, insize); + if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) { + free(convbuf); + return 0; + } + indata = convbuf; /* switch to the converted buffer */ + } +#else + (void)data; +#endif + + while(insize > 0) { + for (i = inputparts = 0; i < 3; i++) { + if(insize > 0) { + inputparts++; + ibuf[i] = *indata; + indata++; + insize--; + } + else + ibuf[i] = 0; + } + + obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); + obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ + ((ibuf[1] & 0xF0) >> 4)); + obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ + ((ibuf[2] & 0xC0) >> 6)); + obuf[3] = (unsigned char) (ibuf[2] & 0x3F); + + switch(inputparts) { + case 1: /* only one byte read */ + snprintf(output, 5, "%c%c==", + table64[obuf[0]], + table64[obuf[1]]); + break; + case 2: /* two bytes read */ + snprintf(output, 5, "%c%c%c=", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]]); + break; + default: + snprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]] ); + break; + } + output += 4; + } + *output=0; + *outptr = base64data; /* make it return the actual data memory */ + +#ifdef CURL_DOES_CONVERSIONS + if(data) + free(convbuf); +#endif + return strlen(base64data); /* return the length of the new data */ +} +/* ---- End of Base64 Encoding ---- */ + +/************* TEST HARNESS STUFF ****************/ + + +#ifdef TEST_ENCODE +/* encoding test harness. Read in standard input and write out the length + * returned by Curl_base64_encode, followed by the base64'd data itself + */ +#include + +#define TEST_NEED_SUCK +void *suck(int *); + +int main(int argc, char **argv, char **envp) +{ + char *base64; + size_t base64Len; + unsigned char *data; + int dataLen; + struct SessionHandle *handle = NULL; + +#ifdef CURL_DOES_CONVERSIONS + /* get a Curl handle so Curl_base64_encode can translate properly */ + handle = curl_easy_init(); + if(handle == NULL) { + fprintf(stderr, "Error: curl_easy_init failed\n"); + return 0; + } +#endif + data = (unsigned char *)suck(&dataLen); + base64Len = Curl_base64_encode(handle, data, dataLen, &base64); + + fprintf(stderr, "%d\n", base64Len); + fprintf(stdout, "%s\n", base64); + + free(base64); free(data); +#ifdef CURL_DOES_CONVERSIONS + curl_easy_cleanup(handle); +#endif + return 0; +} +#endif + +#ifdef TEST_DECODE +/* decoding test harness. Read in a base64 string from stdin and write out the + * length returned by Curl_base64_decode, followed by the decoded data itself + * + * gcc -DTEST_DECODE base64.c -o base64 mprintf.o memdebug.o + */ +#include + +#define TEST_NEED_SUCK +void *suck(int *); + +int main(int argc, char **argv, char **envp) +{ + char *base64; + int base64Len; + unsigned char *data; + int dataLen; + int i, j; +#ifdef CURL_DOES_CONVERSIONS + /* get a Curl handle so main can translate properly */ + struct SessionHandle *handle = curl_easy_init(); + if(handle == NULL) { + fprintf(stderr, "Error: curl_easy_init failed\n"); + return 0; + } +#endif + + base64 = (char *)suck(&base64Len); + dataLen = Curl_base64_decode(base64, &data); + + fprintf(stderr, "%d\n", dataLen); + + for(i=0; i < dataLen; i+=0x10) { + printf("0x%02x: ", i); + for(j=0; j < 0x10; j++) + if((j+i) < dataLen) + printf("%02x ", data[i+j]); + else + printf(" "); + + printf(" | "); + + for(j=0; j < 0x10; j++) + if((j+i) < dataLen) { +#ifdef CURL_DOES_CONVERSIONS + if(CURLE_OK != + Curl_convert_from_network(handle, &data[i+j], (size_t)1)) + data[i+j] = '.'; +#endif /* CURL_DOES_CONVERSIONS */ + printf("%c", ISGRAPH(data[i+j])?data[i+j]:'.'); + } else + break; + puts(""); + } + +#ifdef CURL_DOES_CONVERSIONS + curl_easy_cleanup(handle); +#endif + free(base64); free(data); + return 0; +} +#endif + +#ifdef TEST_NEED_SUCK +/* this function 'sucks' in as much as possible from stdin */ +void *suck(int *lenptr) +{ + int cursize = 8192; + unsigned char *buf = NULL; + int lastread; + int len = 0; + + do { + cursize *= 2; + buf = (unsigned char *)realloc(buf, cursize); + memset(buf + len, 0, cursize - len); + lastread = fread(buf + len, 1, cursize - len, stdin); + len += lastread; + } while(!feof(stdin)); + + lenptr[0] = len; + return (void *)buf; +} +#endif diff --git a/Utilities/cmcurl/lib/base64.h b/Utilities/cmcurl/lib/base64.h new file mode 100644 index 0000000..59742bc --- /dev/null +++ b/Utilities/cmcurl/lib/base64.h @@ -0,0 +1,28 @@ +#ifndef __BASE64_H +#define __BASE64_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +size_t Curl_base64_encode(struct SessionHandle *data, + const char *input, size_t size, char **str); +size_t Curl_base64_decode(const char *source, unsigned char **outptr); +#endif diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c new file mode 100644 index 0000000..2b38972 --- /dev/null +++ b/Utilities/cmcurl/lib/connect.c @@ -0,0 +1,905 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef WIN32 +/* headers for non-win32 */ +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include /* may need it */ +#endif +#ifdef HAVE_NETINET_TCP_H +#include /* for TCP_NODELAY */ +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototype, without it, this crashes + on macos 68K */ +#endif +#if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__)) +#include +#endif +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif +#ifdef VMS +#include +#include +#endif + +#endif +#include +#include +#include + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifdef USE_WINSOCK +#define EINPROGRESS WSAEINPROGRESS +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EISCONN WSAEISCONN +#define ENOTSOCK WSAENOTSOCK +#define ECONNREFUSED WSAECONNREFUSED +#endif + +#include "urldata.h" +#include "sendf.h" +#include "if2ip.h" +#include "strerror.h" +#include "connect.h" +#include "memory.h" +#include "select.h" +#include "url.h" /* for Curl_safefree() */ +#include "multiif.h" +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "inet_ntop.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +static bool verifyconnect(curl_socket_t sockfd, int *error); + +static curl_socket_t +singleipconnect(struct connectdata *conn, + const Curl_addrinfo *ai, /* start connecting to this */ + long timeout_ms, + bool *connected); + +/* + * Curl_sockerrno() returns the *socket-related* errno (or equivalent) on this + * platform to hide platform specific for the function that calls this. + */ +int Curl_sockerrno(void) +{ +#ifdef USE_WINSOCK + return (int)WSAGetLastError(); +#else + return errno; +#endif +} + +/* + * Curl_nonblock() set the given socket to either blocking or non-blocking + * mode based on the 'nonblock' boolean argument. This function is highly + * portable. + */ +int Curl_nonblock(curl_socket_t sockfd, /* operate on this */ + int nonblock /* TRUE or FALSE */) +{ +#undef SETBLOCK +#define SETBLOCK 0 +#ifdef HAVE_O_NONBLOCK + /* most recent unix versions */ + int flags; + + flags = fcntl(sockfd, F_GETFL, 0); + if (TRUE == nonblock) + return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + else + return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); +#undef SETBLOCK +#define SETBLOCK 1 +#endif + +#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) + /* older unix versions */ + int flags; + + flags = nonblock; + return ioctl(sockfd, FIONBIO, &flags); +#undef SETBLOCK +#define SETBLOCK 2 +#endif + +#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) + /* Windows? */ + unsigned long flags; + flags = nonblock; + + return ioctlsocket(sockfd, FIONBIO, &flags); +#undef SETBLOCK +#define SETBLOCK 3 +#endif + +#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) + /* presumably for Amiga */ + return IoctlSocket(sockfd, FIONBIO, (long)nonblock); +#undef SETBLOCK +#define SETBLOCK 4 +#endif + +#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) + /* BeOS */ + long b = nonblock ? 1 : 0; + return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); +#undef SETBLOCK +#define SETBLOCK 5 +#endif + +#ifdef HAVE_DISABLED_NONBLOCKING + return 0; /* returns success */ +#undef SETBLOCK +#define SETBLOCK 6 +#endif + +#if (SETBLOCK == 0) +#error "no non-blocking method was found/used/set" +#endif +} + +/* + * waitconnect() waits for a TCP connect on the given socket for the specified + * number if milliseconds. It returns: + * 0 fine connect + * -1 select() error + * 1 select() timeout + * 2 select() returned with an error condition fd_set + */ + +#define WAITCONN_CONNECTED 0 +#define WAITCONN_SELECT_ERROR -1 +#define WAITCONN_TIMEOUT 1 +#define WAITCONN_FDSET_ERROR 2 + +static +int waitconnect(curl_socket_t sockfd, /* socket */ + long timeout_msec) +{ + int rc; +#ifdef mpeix + /* Call this function once now, and ignore the results. We do this to + "clear" the error state on the socket so that we can later read it + reliably. This is reported necessary on the MPE/iX operating system. */ + (void)verifyconnect(sockfd, NULL); +#endif + + /* now select() until we get connect or timeout */ + rc = Curl_select(CURL_SOCKET_BAD, sockfd, (int)timeout_msec); + if(-1 == rc) + /* error, no connect here, try next */ + return WAITCONN_SELECT_ERROR; + + else if(0 == rc) + /* timeout, no connect today */ + return WAITCONN_TIMEOUT; + + if(rc & CSELECT_ERR) + /* error condition caught */ + return WAITCONN_FDSET_ERROR; + + /* we have a connect! */ + return WAITCONN_CONNECTED; +} + +static CURLcode bindlocal(struct connectdata *conn, + curl_socket_t sockfd) +{ + struct SessionHandle *data = conn->data; + struct sockaddr_in me; + struct sockaddr *sock = NULL; /* bind to this address */ + socklen_t socksize; /* size of the data sock points to */ + unsigned short port = data->set.localport; /* use this port number, 0 for + "random" */ + /* how many port numbers to try to bind to, increasing one at a time */ + int portnum = data->set.localportrange; + + /************************************************************* + * Select device to bind socket to + *************************************************************/ + if (data->set.device && (strlen(data->set.device)<255) ) { + struct Curl_dns_entry *h=NULL; + char myhost[256] = ""; + in_addr_t in; + int rc; + bool was_iface = FALSE; + + /* First check if the given name is an IP address */ + in=inet_addr(data->set.device); + + if((in == CURL_INADDR_NONE) && + Curl_if2ip(data->set.device, myhost, sizeof(myhost))) { + /* + * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer + */ + rc = Curl_resolv(conn, myhost, 0, &h); + if(rc == CURLRESOLV_PENDING) + (void)Curl_wait_for_resolv(conn, &h); + + if(h) { + was_iface = TRUE; + Curl_resolv_unlock(data, h); + } + } + + if(!was_iface) { + /* + * This was not an interface, resolve the name as a host name + * or IP number + */ + rc = Curl_resolv(conn, data->set.device, 0, &h); + if(rc == CURLRESOLV_PENDING) + (void)Curl_wait_for_resolv(conn, &h); + + if(h) { + if(in == CURL_INADDR_NONE) + /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ + Curl_inet_ntop(h->addr->ai_addr->sa_family, + &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr, + myhost, sizeof myhost); + else + /* we know data->set.device is shorter than the myhost array */ + strcpy(myhost, data->set.device); + Curl_resolv_unlock(data, h); + } + } + + if(! *myhost) { + /* need to fix this + h=Curl_gethost(data, + getmyhost(*myhost,sizeof(myhost)), + hostent_buf, + sizeof(hostent_buf)); + */ + failf(data, "Couldn't bind to '%s'", data->set.device); + return CURLE_HTTP_PORT_FAILED; + } + + infof(data, "Bind local address to %s\n", myhost); + +#ifdef SO_BINDTODEVICE + /* I am not sure any other OSs than Linux that provide this feature, and + * at the least I cannot test. --Ben + * + * This feature allows one to tightly bind the local socket to a + * particular interface. This will force even requests to other local + * interfaces to go out the external interface. + * + */ + if (was_iface) { + /* Only bind to the interface when specified as interface, not just as a + * hostname or ip address. + */ + if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + data->set.device, strlen(data->set.device)+1) != 0) { + /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n", + sockfd, data->set.device, Curl_strerror(Curl_sockerrno())); */ + infof(data, "SO_BINDTODEVICE %s failed\n", + data->set.device); + /* This is typically "errno 1, error: Operation not permitted" if + you're not running as root or another suitable privileged user */ + } + } +#endif + + in=inet_addr(myhost); + if (CURL_INADDR_NONE == in) { + failf(data,"couldn't find my own IP address (%s)", myhost); + return CURLE_HTTP_PORT_FAILED; + } /* end of inet_addr */ + + if ( h ) { + Curl_addrinfo *addr = h->addr; + sock = addr->ai_addr; + socksize = addr->ai_addrlen; + } + else + return CURLE_HTTP_PORT_FAILED; + + } + else if(port) { + /* if a local port number is requested but no local IP, extract the + address from the socket */ + memset(&me, 0, sizeof(struct sockaddr)); + me.sin_family = AF_INET; + me.sin_addr.s_addr = INADDR_ANY; + + sock = (struct sockaddr *)&me; + socksize = sizeof(struct sockaddr); + + } + else + /* no local kind of binding was requested */ + return CURLE_OK; + + do { + + /* Set port number to bind to, 0 makes the system pick one */ + if(sock->sa_family == AF_INET) + ((struct sockaddr_in *)sock)->sin_port = htons(port); +#ifdef ENABLE_IPV6 + else + ((struct sockaddr_in6 *)sock)->sin6_port = htons(port); +#endif + + if( bind(sockfd, sock, socksize) >= 0) { + /* we succeeded to bind */ + struct Curl_sockaddr_storage add; + socklen_t size; + + size = sizeof(add); + if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { + failf(data, "getsockname() failed"); + return CURLE_HTTP_PORT_FAILED; + } + /* We re-use/clobber the port variable here below */ + if(((struct sockaddr *)&add)->sa_family == AF_INET) + port = ntohs(((struct sockaddr_in *)&add)->sin_port); +#ifdef ENABLE_IPV6 + else + port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port); +#endif + infof(data, "Local port: %d\n", port); + return CURLE_OK; + } + if(--portnum > 0) { + infof(data, "Bind to local port %d failed, trying next\n", port); + port++; /* try next port */ + } + else + break; + } while(1); + + data->state.os_errno = Curl_sockerrno(); + failf(data, "bind failure: %s", + Curl_strerror(conn, data->state.os_errno)); + return CURLE_HTTP_PORT_FAILED; + +} + +/* + * verifyconnect() returns TRUE if the connect really has happened. + */ +static bool verifyconnect(curl_socket_t sockfd, int *error) +{ + bool rc = TRUE; +#ifdef SO_ERROR + int err = 0; + socklen_t errSize = sizeof(err); + +#ifdef WIN32 + /* + * In October 2003 we effectively nullified this function on Windows due to + * problems with it using all CPU in multi-threaded cases. + * + * In May 2004, we bring it back to offer more info back on connect failures. + * Gisle Vanem could reproduce the former problems with this function, but + * could avoid them by adding this SleepEx() call below: + * + * "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. + * + * Someone got to verify this on Win-NT 4.0, 2000." + */ + +#ifdef _WIN32_WCE + Sleep(0); +#else + SleepEx(0, FALSE); +#endif + +#endif + + if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR, + (void *)&err, &errSize)) + err = Curl_sockerrno(); + +#ifdef _WIN32_WCE + /* Always returns this error, bug in CE? */ + if(WSAENOPROTOOPT==err) + err=0; +#endif + + if ((0 == err) || (EISCONN == err)) + /* we are connected, awesome! */ + rc = TRUE; + else + /* This wasn't a successful connect */ + rc = FALSE; + if (error) + *error = err; +#else + (void)sockfd; + if (error) + *error = Curl_sockerrno(); +#endif + return rc; +} + +CURLcode Curl_store_ip_addr(struct connectdata *conn) +{ + char addrbuf[256]; + Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf)); + + /* save the string */ + Curl_safefree(conn->ip_addr_str); + conn->ip_addr_str = strdup(addrbuf); + if(!conn->ip_addr_str) + return CURLE_OUT_OF_MEMORY; /* FAIL */ + +#ifdef PF_INET6 + if(conn->ip_addr->ai_family == PF_INET6) + conn->bits.ipv6 = TRUE; +#endif + + return CURLE_OK; +} + +/* Used within the multi interface. Try next IP address, return TRUE if no + more address exists */ +static bool trynextip(struct connectdata *conn, + int sockindex, + bool *connected) +{ + curl_socket_t sockfd; + Curl_addrinfo *ai; + + /* first close the failed socket */ + sclose(conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + *connected = FALSE; + + if(sockindex != FIRSTSOCKET) + return TRUE; /* no next */ + + /* try the next address */ + ai = conn->ip_addr->ai_next; + + while (ai) { + sockfd = singleipconnect(conn, ai, 0L, connected); + if(sockfd != CURL_SOCKET_BAD) { + /* store the new socket descriptor */ + conn->sock[sockindex] = sockfd; + conn->ip_addr = ai; + + Curl_store_ip_addr(conn); + return FALSE; + } + ai = ai->ai_next; + } + return TRUE; +} + +/* + * Curl_is_connected() is used from the multi interface to check if the + * firstsocket has connected. + */ + +CURLcode Curl_is_connected(struct connectdata *conn, + int sockindex, + bool *connected) +{ + int rc; + struct SessionHandle *data = conn->data; + CURLcode code = CURLE_OK; + curl_socket_t sockfd = conn->sock[sockindex]; + long allow = DEFAULT_CONNECT_TIMEOUT; + long allow_total = 0; + long has_passed; + + curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); + + *connected = FALSE; /* a very negative world view is best */ + + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + + /* subtract the most strict timeout of the ones */ + if(data->set.timeout && data->set.connecttimeout) { + if (data->set.timeout < data->set.connecttimeout) + allow_total = allow = data->set.timeout*1000; + else + allow = data->set.connecttimeout*1000; + } + else if(data->set.timeout) { + allow_total = allow = data->set.timeout*1000; + } + else if(data->set.connecttimeout) { + allow = data->set.connecttimeout*1000; + } + + if(has_passed > allow ) { + /* time-out, bail out, go home */ + failf(data, "Connection time-out after %ld ms", has_passed); + return CURLE_OPERATION_TIMEOUTED; + } + if(conn->bits.tcpconnect) { + /* we are connected already! */ + Curl_expire(data, allow_total); + *connected = TRUE; + return CURLE_OK; + } + + Curl_expire(data, allow); + + /* check for connect without timeout as we want to return immediately */ + rc = waitconnect(sockfd, 0); + + if(WAITCONN_CONNECTED == rc) { + int error; + if (verifyconnect(sockfd, &error)) { + /* we are connected, awesome! */ + *connected = TRUE; + return CURLE_OK; + } + /* nope, not connected for real */ + data->state.os_errno = error; + infof(data, "Connection failed\n"); + if(trynextip(conn, sockindex, connected)) { + code = CURLE_COULDNT_CONNECT; + } + } + else if(WAITCONN_TIMEOUT != rc) { + int error = 0; + + /* nope, not connected */ + if (WAITCONN_FDSET_ERROR == rc) { + (void)verifyconnect(sockfd, &error); + data->state.os_errno = error; + infof(data, "%s\n",Curl_strerror(conn,error)); + } + else + infof(data, "Connection failed\n"); + + if(trynextip(conn, sockindex, connected)) { + error = Curl_sockerrno(); + data->state.os_errno = error; + failf(data, "Failed connect to %s:%d; %s", + conn->host.name, conn->port, Curl_strerror(conn,error)); + code = CURLE_COULDNT_CONNECT; + } + } + /* + * If the connection failed here, we should attempt to connect to the "next + * address" for the given host. + */ + + return code; +} + +static void tcpnodelay(struct connectdata *conn, + curl_socket_t sockfd) +{ +#ifdef TCP_NODELAY + struct SessionHandle *data= conn->data; + socklen_t onoff = (socklen_t) data->set.tcp_nodelay; + int proto = IPPROTO_TCP; + +#ifdef HAVE_GETPROTOBYNAME + struct protoent *pe = getprotobyname("tcp"); + if (pe) + proto = pe->p_proto; +#endif + + if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff, + sizeof(onoff)) < 0) + infof(data, "Could not set TCP_NODELAY: %s\n", + Curl_strerror(conn, Curl_sockerrno())); + else + infof(data,"TCP_NODELAY set\n"); +#else + (void)conn; + (void)sockfd; +#endif +} + +#ifdef SO_NOSIGPIPE +/* 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? */ +static void nosigpipe(struct connectdata *conn, + curl_socket_t sockfd) +{ + struct SessionHandle *data= conn->data; + int onoff = 1; + if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, + sizeof(onoff)) < 0) + infof(data, "Could not set SO_NOSIGPIPE: %s\n", + Curl_strerror(conn, Curl_sockerrno())); +} +#else +#define nosigpipe(x,y) +#endif + +/* singleipconnect() connects to the given IP only, and it may return without + having connected if used from the multi interface. */ +static curl_socket_t +singleipconnect(struct connectdata *conn, + const Curl_addrinfo *ai, + long timeout_ms, + bool *connected) +{ + char addr_buf[128]; + int rc; + int error; + bool isconnected; + struct SessionHandle *data = conn->data; + curl_socket_t sockfd; + CURLcode res; + + sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol); + if (sockfd == CURL_SOCKET_BAD) + return CURL_SOCKET_BAD; + + *connected = FALSE; /* default is not connected */ + + Curl_printable_address(ai, addr_buf, sizeof(addr_buf)); + infof(data, " Trying %s... ", addr_buf); + + if(data->set.tcp_nodelay) + tcpnodelay(conn, sockfd); + + nosigpipe(conn, sockfd); + + if(data->set.fsockopt) { + /* activate callback for setting socket options */ + error = data->set.fsockopt(data->set.sockopt_client, + sockfd, + CURLSOCKTYPE_IPCXN); + if (error) { + sclose(sockfd); /* close the socket and bail out */ + return CURL_SOCKET_BAD; + } + } + + /* possibly bind the local end to an IP, interface or port */ + res = bindlocal(conn, sockfd); + if(res) { + sclose(sockfd); /* close socket and bail out */ + return CURL_SOCKET_BAD; + } + + /* set socket non-blocking */ + Curl_nonblock(sockfd, TRUE); + + /* Connect TCP sockets, bind UDP */ + if(conn->socktype == SOCK_STREAM) + rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); + else + rc = 0; + + if(-1 == rc) { + error = Curl_sockerrno(); + + switch (error) { + case EINPROGRESS: + case EWOULDBLOCK: +#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK + /* On some platforms EAGAIN and EWOULDBLOCK are the + * same value, and on others they are different, hence + * the odd #if + */ + case EAGAIN: +#endif + rc = waitconnect(sockfd, timeout_ms); + break; + default: + /* unknown error, fallthrough and try another address! */ + failf(data, "Failed to connect to %s: %s", + addr_buf, Curl_strerror(conn,error)); + data->state.os_errno = error; + break; + } + } + + /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from + connect(). We can be sure of this since connect() cannot return 1. */ + if((WAITCONN_TIMEOUT == rc) && + (data->state.used_interface == Curl_if_multi)) { + /* Timeout when running the multi interface */ + return sockfd; + } + + isconnected = verifyconnect(sockfd, &error); + + if(!rc && isconnected) { + /* we are connected, awesome! */ + *connected = TRUE; /* this is a true connect */ + infof(data, "connected\n"); + return sockfd; + } + else if(WAITCONN_TIMEOUT == rc) + infof(data, "Timeout\n"); + else { + data->state.os_errno = error; + infof(data, "%s\n", Curl_strerror(conn, error)); + } + + /* connect failed or timed out */ + sclose(sockfd); + + return CURL_SOCKET_BAD; +} + +/* + * TCP connect to the given host with timeout, proxy or remote doesn't matter. + * There might be more than one IP address to try out. Fill in the passed + * pointer with the connected socket. + */ + +CURLcode Curl_connecthost(struct connectdata *conn, /* context */ + const struct Curl_dns_entry *remotehost, /* use this one */ + curl_socket_t *sockconn, /* the connected socket */ + Curl_addrinfo **addr, /* the one we used */ + bool *connected) /* really connected? */ +{ + struct SessionHandle *data = conn->data; + curl_socket_t sockfd = CURL_SOCKET_BAD; + int aliasindex; + int num_addr; + Curl_addrinfo *ai; + Curl_addrinfo *curr_addr; + + struct timeval after; + struct timeval before = Curl_tvnow(); + + /************************************************************* + * Figure out what maximum time we have left + *************************************************************/ + long timeout_ms= DEFAULT_CONNECT_TIMEOUT; + long timeout_per_addr; + + *connected = FALSE; /* default to not connected */ + + if(data->set.timeout || data->set.connecttimeout) { + long has_passed; + + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + + /* get the most strict timeout of the ones converted to milliseconds */ + if(data->set.timeout && data->set.connecttimeout) { + if (data->set.timeout < data->set.connecttimeout) + timeout_ms = data->set.timeout*1000; + else + timeout_ms = data->set.connecttimeout*1000; + } + else if(data->set.timeout) + timeout_ms = data->set.timeout*1000; + else + timeout_ms = data->set.connecttimeout*1000; + + /* subtract the passed time */ + timeout_ms -= has_passed; + + if(timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "Connection time-out"); + return CURLE_OPERATION_TIMEOUTED; + } + } + Curl_expire(data, timeout_ms); + + /* Max time for each address */ + num_addr = Curl_num_addresses(remotehost->addr); + timeout_per_addr = timeout_ms / num_addr; + + ai = remotehost->addr; + + /* Below is the loop that attempts to connect to all IP-addresses we + * know for the given host. One by one until one IP succeeds. + */ + + if(data->state.used_interface == Curl_if_multi) + /* don't hang when doing multi */ + timeout_per_addr = 0; + + /* + * Connecting with a Curl_addrinfo chain + */ + for (curr_addr = ai, aliasindex=0; curr_addr; + curr_addr = curr_addr->ai_next, aliasindex++) { + + /* start connecting to the IP curr_addr points to */ + sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected); + + if(sockfd != CURL_SOCKET_BAD) + break; + + /* get a new timeout for next attempt */ + after = Curl_tvnow(); + timeout_ms -= Curl_tvdiff(after, before); + if(timeout_ms < 0) { + failf(data, "connect() timed out!"); + return CURLE_OPERATION_TIMEOUTED; + } + before = after; + } /* end of connect-to-each-address loop */ + + if (sockfd == CURL_SOCKET_BAD) { + /* no good connect was made */ + *sockconn = CURL_SOCKET_BAD; + failf(data, "couldn't connect to host"); + return CURLE_COULDNT_CONNECT; + } + + /* leave the socket in non-blocking mode */ + + /* store the address we use */ + if(addr) + *addr = curr_addr; + + /* allow NULL-pointers to get passed in */ + if(sockconn) + *sockconn = sockfd; /* the socket descriptor we've connected */ + + data->info.numconnects++; /* to track the number of connections made */ + + return CURLE_OK; +} diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h new file mode 100644 index 0000000..599572b --- /dev/null +++ b/Utilities/cmcurl/lib/connect.h @@ -0,0 +1,46 @@ +#ifndef __CONNECT_H +#define __CONNECT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +int Curl_nonblock(curl_socket_t sockfd, /* operate on this */ + int nonblock /* TRUE or FALSE */); + +CURLcode Curl_is_connected(struct connectdata *conn, + int sockindex, + bool *connected); + +CURLcode Curl_connecthost(struct connectdata *conn, + const struct Curl_dns_entry *host, /* connect to this */ + curl_socket_t *sockconn, /* not set if error */ + Curl_addrinfo **addr, /* the one we used */ + bool *connected /* truly connected? */ + ); + +int Curl_sockerrno(void); + +CURLcode Curl_store_ip_addr(struct connectdata *conn); + +#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ + +#endif diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c new file mode 100644 index 0000000..97f8341 --- /dev/null +++ b/Utilities/cmcurl/lib/content_encoding.c @@ -0,0 +1,424 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_LIBZ + +#include +#include + +#include "urldata.h" +#include +#include "sendf.h" +#include "content_encoding.h" +#include "memory.h" + +#include "memdebug.h" + +/* Comment this out if zlib is always going to be at least ver. 1.2.0.4 + (doing so will reduce code size slightly). */ +#define OLD_ZLIB_SUPPORT 1 + +#define DSIZ 0x10000 /* buffer size for decompressed data */ + +#define GZIP_MAGIC_0 0x1f +#define GZIP_MAGIC_1 0x8b + +/* gzip flag byte */ +#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 file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +enum zlibState { + ZLIB_UNINIT, /* uninitialized */ + ZLIB_INIT, /* initialized */ + ZLIB_GZIP_HEADER, /* reading gzip header */ + ZLIB_GZIP_INFLATING, /* inflating gzip stream */ + ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ +}; + +static CURLcode +process_zlib_error(struct connectdata *conn, z_stream *z) +{ + struct SessionHandle *data = conn->data; + if (z->msg) + failf (data, "Error while processing content unencoding: %s", + z->msg); + else + failf (data, "Error while processing content unencoding: " + "Unknown failure within decompression software."); + + return CURLE_BAD_CONTENT_ENCODING; +} + +static CURLcode +exit_zlib(z_stream *z, bool *zlib_init, CURLcode result) +{ + inflateEnd(z); + *zlib_init = ZLIB_UNINIT; + return result; +} + +static CURLcode +inflate_stream(struct connectdata *conn, + struct Curl_transfer_keeper *k) +{ + int allow_restart = 1; + z_stream *z = &k->z; /* zlib state structure */ + uInt nread = z->avail_in; + Bytef *orig_in = z->next_in; + int status; /* zlib status */ + CURLcode result = CURLE_OK; /* Curl_client_write status */ + char *decomp; /* Put the decompressed data here. */ + + /* Dynamically allocate a buffer for decompression because it's uncommonly + large to hold on the stack */ + decomp = (char*)malloc(DSIZ); + if (decomp == NULL) { + return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); + } + + /* because the buffer size is fixed, iteratively decompress and transfer to + the client via client_write. */ + for (;;) { + /* (re)set buffer for decompressed output for every iteration */ + z->next_out = (Bytef *)decomp; + z->avail_out = DSIZ; + + status = inflate(z, Z_SYNC_FLUSH); + if (status == Z_OK || status == Z_STREAM_END) { + allow_restart = 0; + if(DSIZ - z->avail_out) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp, + DSIZ - z->avail_out); + /* if !CURLE_OK, clean up, return */ + if (result) { + free(decomp); + return exit_zlib(z, &k->zlib_init, result); + } + } + + /* Done? clean up, return */ + if (status == Z_STREAM_END) { + free(decomp); + if (inflateEnd(z) == Z_OK) + return exit_zlib(z, &k->zlib_init, result); + else + return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); + } + + /* Done with these bytes, exit */ + if (status == Z_OK && z->avail_in == 0) { + free(decomp); + return result; + } + } + else if (allow_restart && status == Z_DATA_ERROR) { + /* some servers seem to not generate zlib headers, so this is an attempt + to fix and continue anyway */ + + inflateReset(z); + if (inflateInit2(z, -MAX_WBITS) != Z_OK) { + return process_zlib_error(conn, z); + } + z->next_in = orig_in; + z->avail_in = nread; + allow_restart = 0; + continue; + } + else { /* Error; exit loop, handle below */ + free(decomp); + return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); + } + } + /* Will never get here */ +} + +CURLcode +Curl_unencode_deflate_write(struct connectdata *conn, + struct Curl_transfer_keeper *k, + ssize_t nread) +{ + z_stream *z = &k->z; /* zlib state structure */ + + /* Initialize zlib? */ + if (k->zlib_init == ZLIB_UNINIT) { + z->zalloc = (alloc_func)Z_NULL; + z->zfree = (free_func)Z_NULL; + z->opaque = 0; + z->next_in = NULL; + z->avail_in = 0; + if (inflateInit(z) != Z_OK) + return process_zlib_error(conn, z); + k->zlib_init = ZLIB_INIT; + } + + /* Set the compressed input when this function is called */ + z->next_in = (Bytef *)k->str; + z->avail_in = (uInt)nread; + + /* Now uncompress the data */ + return inflate_stream(conn, k); +} + +#ifdef OLD_ZLIB_SUPPORT +/* Skip over the gzip header */ +static enum { + GZIP_OK, + GZIP_BAD, + GZIP_UNDERFLOW +} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen) +{ + int method, flags; + const ssize_t totallen = len; + + /* The shortest header is 10 bytes */ + if (len < 10) + return GZIP_UNDERFLOW; + + if ((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1)) + return GZIP_BAD; + + method = data[2]; + flags = data[3]; + + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + /* Can't handle this compression method or unknown flag */ + return GZIP_BAD; + } + + /* Skip over time, xflags, OS code and all previous bytes */ + len -= 10; + data += 10; + + if (flags & EXTRA_FIELD) { + ssize_t extra_len; + + if (len < 2) + return GZIP_UNDERFLOW; + + extra_len = (data[1] << 8) | data[0]; + + if (len < (extra_len+2)) + return GZIP_UNDERFLOW; + + len -= (extra_len + 2); + data += (extra_len + 2); + } + + if (flags & ORIG_NAME) { + /* Skip over NUL-terminated file name */ + while (len && *data) { + --len; + ++data; + } + if (!len || *data) + return GZIP_UNDERFLOW; + + /* Skip over the NUL */ + --len; + ++data; + } + + if (flags & COMMENT) { + /* Skip over NUL-terminated comment */ + while (len && *data) { + --len; + ++data; + } + if (!len || *data) + return GZIP_UNDERFLOW; + + /* Skip over the NUL */ + --len; + ++data; + } + + if (flags & HEAD_CRC) { + if (len < 2) + return GZIP_UNDERFLOW; + + len -= 2; + data += 2; + } + + *headerlen = totallen - len; + return GZIP_OK; +} +#endif + +CURLcode +Curl_unencode_gzip_write(struct connectdata *conn, + struct Curl_transfer_keeper *k, + ssize_t nread) +{ + z_stream *z = &k->z; /* zlib state structure */ + + /* Initialize zlib? */ + if (k->zlib_init == ZLIB_UNINIT) { + z->zalloc = (alloc_func)Z_NULL; + z->zfree = (free_func)Z_NULL; + z->opaque = 0; + z->next_in = NULL; + z->avail_in = 0; + + if (strcmp(zlibVersion(), "1.2.0.4") >= 0) { + /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ + if (inflateInit2(z, MAX_WBITS+32) != Z_OK) { + return process_zlib_error(conn, z); + } + k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ + + } else { + /* we must parse the gzip header ourselves */ + if (inflateInit2(z, -MAX_WBITS) != Z_OK) { + return process_zlib_error(conn, z); + } + k->zlib_init = ZLIB_INIT; /* Initial call state */ + } + } + + if (k->zlib_init == ZLIB_INIT_GZIP) { + /* Let zlib handle the gzip decompression entirely */ + z->next_in = (Bytef *)k->str; + z->avail_in = (uInt)nread; + /* Now uncompress the data */ + return inflate_stream(conn, k); + } + +#ifndef OLD_ZLIB_SUPPORT + /* Support for old zlib versions is compiled away and we are running with + an old version, so return an error. */ + return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND); + +#else + /* 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 + * can handle the gzip header themselves. + */ + + switch (k->zlib_init) { + /* Skip over gzip header? */ + case ZLIB_INIT: + { + /* Initial call state */ + ssize_t hlen; + + switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) { + case GZIP_OK: + z->next_in = (Bytef *)k->str + hlen; + z->avail_in = (uInt)(nread - hlen); + k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ + break; + + case GZIP_UNDERFLOW: + /* 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's unlikely + * that circumstances will be right for this code path to be followed in + * 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)nread; + z->next_in = malloc(z->avail_in); + if (z->next_in == NULL) { + return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); + } + memcpy(z->next_in, k->str, z->avail_in); + k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */ + /* We don't have any data to inflate yet */ + return CURLE_OK; + + case GZIP_BAD: + default: + return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); + } + + } + break; + + case ZLIB_GZIP_HEADER: + { + /* Need more gzip header data state */ + ssize_t hlen; + unsigned char *oldblock = z->next_in; + + z->avail_in += nread; + z->next_in = realloc(z->next_in, z->avail_in); + if (z->next_in == NULL) { + free(oldblock); + return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); + } + /* Append the new block of data to the previous one */ + memcpy(z->next_in + z->avail_in - nread, k->str, nread); + + switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) { + case GZIP_OK: + /* This is the zlib stream data */ + free(z->next_in); + /* Don't point into the malloced block since we just freed it */ + z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in; + z->avail_in = (uInt)(z->avail_in - hlen); + k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ + break; + + case GZIP_UNDERFLOW: + /* We still don't have any data to inflate! */ + return CURLE_OK; + + case GZIP_BAD: + default: + free(z->next_in); + return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); + } + + } + break; + + case ZLIB_GZIP_INFLATING: + default: + /* Inflating stream state */ + z->next_in = (Bytef *)k->str; + z->avail_in = (uInt)nread; + break; + } + + if (z->avail_in == 0) { + /* We don't have any data to inflate; wait until next time */ + return CURLE_OK; + } + + /* We've parsed the header, now uncompress the data */ + return inflate_stream(conn, k); +#endif +} +#endif /* HAVE_LIBZ */ diff --git a/Utilities/cmcurl/lib/content_encoding.h b/Utilities/cmcurl/lib/content_encoding.h new file mode 100644 index 0000000..b31669b --- /dev/null +++ b/Utilities/cmcurl/lib/content_encoding.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +/* + * Comma-separated list all supported Content-Encodings ('identity' is implied) + */ +#ifdef HAVE_LIBZ +#define ALL_CONTENT_ENCODINGS "deflate, gzip" +#else +#define ALL_CONTENT_ENCODINGS "identity" +#endif + +CURLcode Curl_unencode_deflate_write(struct connectdata *conn, + struct Curl_transfer_keeper *k, + ssize_t nread); + +CURLcode +Curl_unencode_gzip_write(struct connectdata *conn, + struct Curl_transfer_keeper *k, + ssize_t nread); diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c new file mode 100644 index 0000000..d8ea241 --- /dev/null +++ b/Utilities/cmcurl/lib/cookie.c @@ -0,0 +1,1019 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/*** + + +RECEIVING COOKIE INFORMATION +============================ + +struct CookieInfo *cookie_init(char *file); + + Inits a cookie struct to store data in a local file. This is always + called before any cookies are set. + +int cookies_set(struct CookieInfo *cookie, char *cookie_line); + + The 'cookie_line' parameter is a full "Set-cookie:" line as + received from a server. + + The function need to replace previously stored lines that this new + line superceeds. + + It may remove lines that are expired. + + It should return an indication of success/error. + + +SENDING COOKIE INFORMATION +========================== + +struct Cookies *cookie_getlist(struct CookieInfo *cookie, + char *host, char *path, bool secure); + + For a given host and path, return a linked list of cookies that + the client 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 haven't expired. + + +Example set of cookies: + + Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure + Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/ftgw; secure + Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: + Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday, + 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure +****/ + + +#include "setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + +#include +#include + +#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */ +#include + +#include "urldata.h" +#include "cookie.h" +#include "strequal.h" +#include "strtok.h" +#include "sendf.h" +#include "memory.h" +#include "share.h" +#include "strtoofft.h" + +/* The last #include file should be: */ +#ifdef CURLDEBUG +#include "memdebug.h" +#endif + +#define my_isspace(x) ((x == ' ') || (x == '\t')) + +static void freecookie(struct Cookie *co) +{ + if(co->expirestr) + free(co->expirestr); + if(co->domain) + free(co->domain); + if(co->path) + free(co->path); + if(co->name) + free(co->name); + if(co->value) + free(co->value); + if(co->maxage) + free(co->maxage); + if(co->version) + free(co->version); + + free(co); +} + +static bool tailmatch(const char *little, const char *bigone) +{ + size_t littlelen = strlen(little); + size_t biglen = strlen(bigone); + + if(littlelen > biglen) + return FALSE; + + return (bool)strequal(little, bigone+biglen-littlelen); +} + +/* + * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). + */ +void Curl_cookie_loadfiles(struct SessionHandle *data) +{ + struct curl_slist *list = data->change.cookielist; + if(list) { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + while(list) { + data->cookies = Curl_cookie_init(data, + list->data, + data->cookies, + data->set.cookiesession); + list = list->next; + } + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + curl_slist_free_all(data->change.cookielist); /* clean up list */ + data->change.cookielist = NULL; /* don't do this again! */ + } +} + +/**************************************************************************** + * + * Curl_cookie_add() + * + * Add a single cookie line to the cookie keeping object. + * + ***************************************************************************/ + +struct Cookie * +Curl_cookie_add(struct SessionHandle *data, + /* The 'data' pointer here may be NULL at times, and thus + must only be used very carefully for things that can deal + with data being NULL. Such as infof() and similar */ + + struct CookieInfo *c, + bool httpheader, /* TRUE if HTTP header-style line */ + char *lineptr, /* first character of the line */ + char *domain, /* default domain */ + char *path) /* full path used when this cookie is set, + used to get default path for the cookie + unless set */ +{ + struct Cookie *clist; + char *what; + char name[MAX_NAME]; + char *ptr; + char *semiptr; + struct Cookie *co; + struct Cookie *lastc=NULL; + time_t now = time(NULL); + bool replace_old = FALSE; + bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ + + /* First, alloc and init a new struct for it */ + co = (struct Cookie *)calloc(sizeof(struct Cookie), 1); + if(!co) + return NULL; /* bail out if we're this low on memory */ + + if(httpheader) { + /* This line was read off a HTTP-header */ + char *sep; + + what = malloc(MAX_COOKIE_LINE); + if(!what) { + free(co); + return NULL; + } + + semiptr=strchr(lineptr, ';'); /* first, find a semicolon */ + + while(*lineptr && my_isspace(*lineptr)) + lineptr++; + + ptr = lineptr; + do { + /* we have a = pair or a 'secure' word here */ + sep = strchr(ptr, '='); + if(sep && (!semiptr || (semiptr>sep)) ) { + /* + * There is a = sign and if there was a semicolon too, which make sure + * that the semicolon comes _after_ the equal sign. + */ + + name[0]=what[0]=0; /* init the buffers */ + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%" + MAX_COOKIE_LINE_TXT "[^;\r\n]", + name, what)) { + /* this is a = pair */ + + char *whatptr; + + /* Strip off trailing whitespace from the 'what' */ + size_t len=strlen(what); + while(len && my_isspace(what[len-1])) { + what[len-1]=0; + len--; + } + + /* Skip leading whitespace from the 'what' */ + whatptr=what; + while(my_isspace(*whatptr)) { + whatptr++; + } + + if(strequal("path", name)) { + co->path=strdup(whatptr); + if(!co->path) { + badcookie = TRUE; /* out of memory bad */ + break; + } + } + else if(strequal("domain", name)) { + /* note that this name may or may not have a preceeding dot, but + we don't care about that, we treat the names the same anyway */ + + const char *domptr=whatptr; + int dotcount=1; + + /* Count the dots, we need to make sure that there are enough + of them. */ + + if('.' == whatptr[0]) + /* don't count the initial dot, assume it */ + domptr++; + + do { + domptr = strchr(domptr, '.'); + if(domptr) { + domptr++; + dotcount++; + } + } while(domptr); + + /* The original Netscape cookie spec defined that this domain name + MUST have three dots (or two if one of the seven holy TLDs), + but it seems that these kinds of cookies are in use "out there" + so we cannot be that strict. I've therefore lowered the check + to not allow less than two dots. */ + + if(dotcount < 2) { + /* Received and skipped a cookie with a domain using too few + dots. */ + badcookie=TRUE; /* mark this as a bad cookie */ + infof(data, "skipped cookie with illegal dotcount domain: %s\n", + whatptr); + } + else { + /* Now, we make sure that our host is within the given domain, + or the given domain is not valid and thus cannot be set. */ + + if('.' == whatptr[0]) + whatptr++; /* ignore preceeding dot */ + + if(!domain || tailmatch(whatptr, domain)) { + const char *tailptr=whatptr; + if(tailptr[0] == '.') + tailptr++; + co->domain=strdup(tailptr); /* don't prefix w/dots + internally */ + if(!co->domain) { + badcookie = TRUE; + break; + } + co->tailmatch=TRUE; /* we always do that if the domain name was + given */ + } + else { + /* we did not get a tailmatch and then the attempted set domain + is not a domain to which the current host belongs. Mark as + bad. */ + badcookie=TRUE; + infof(data, "skipped cookie with bad tailmatch domain: %s\n", + whatptr); + } + } + } + else if(strequal("version", name)) { + co->version=strdup(whatptr); + if(!co->version) { + badcookie = TRUE; + break; + } + } + else if(strequal("max-age", name)) { + /* 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 + cookie should be discarded immediately. + + */ + co->maxage = strdup(whatptr); + if(!co->maxage) { + badcookie = TRUE; + break; + } + co->expires = + atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now; + } + else if(strequal("expires", name)) { + co->expirestr=strdup(whatptr); + if(!co->expirestr) { + badcookie = TRUE; + break; + } + co->expires = curl_getdate(what, &now); + } + else if(!co->name) { + co->name = strdup(name); + co->value = strdup(whatptr); + if(!co->name || !co->value) { + badcookie = TRUE; + break; + } + } + /* + else this is the second (or more) name we don't know + about! */ + } + else { + /* this is an "illegal" = pair */ + } + } + else { + if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]", + what)) { + if(strequal("secure", what)) + co->secure = TRUE; + /* else, + unsupported keyword without assign! */ + + } + } + if(!semiptr || !*semiptr) { + /* we already know there are no more cookies */ + semiptr = NULL; + continue; + } + + ptr=semiptr+1; + while(ptr && *ptr && my_isspace(*ptr)) + ptr++; + semiptr=strchr(ptr, ';'); /* now, find the next semicolon */ + + if(!semiptr && *ptr) + /* There are no more semicolons, but there's a final name=value pair + coming up */ + semiptr=strchr(ptr, '\0'); + } while(semiptr); + + if(!badcookie && !co->domain) { + if(domain) { + /* no domain was given in the header line, set the default */ + co->domain=strdup(domain); + if(!co->domain) + badcookie = TRUE; + } + } + + if(!badcookie && !co->path && path) { + /* no path was given in the header line, set the default */ + char *endslash = strrchr(path, '/'); + if(endslash) { + size_t pathlen = endslash-path+1; /* include the ending slash */ + co->path=malloc(pathlen+1); /* one extra for the zero byte */ + if(co->path) { + memcpy(co->path, path, pathlen); + co->path[pathlen]=0; /* zero terminate */ + } + else + badcookie = TRUE; + } + } + + free(what); + + if(badcookie || !co->name) { + /* we didn't get a cookie name or a bad one, + this is an illegal line, bail out */ + freecookie(co); + return NULL; + } + + } + else { + /* This line is NOT a HTTP header style line, we do offer support for + reading the odd netscape cookies-file format here */ + char *firstptr; + char *tok_buf; + int fields; + + if(lineptr[0]=='#') { + /* don't even try the comments */ + free(co); + return NULL; + } + /* strip off the possible end-of-line characters */ + ptr=strchr(lineptr, '\r'); + if(ptr) + *ptr=0; /* clear it */ + ptr=strchr(lineptr, '\n'); + if(ptr) + *ptr=0; /* clear it */ + + firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ + + /* Here's a quick check to eliminate normal HTTP-headers from this */ + if(!firstptr || strchr(firstptr, ':')) { + free(co); + return NULL; + } + + /* Now loop through the fields and init the struct we already have + allocated */ + for(ptr=firstptr, fields=0; ptr && !badcookie; + ptr=strtok_r(NULL, "\t", &tok_buf), fields++) { + switch(fields) { + case 0: + if(ptr[0]=='.') /* skip preceeding dots */ + ptr++; + co->domain = strdup(ptr); + if(!co->domain) + badcookie = TRUE; + break; + case 1: + /* This field got its explanation on the 23rd of May 2001 by + Andrés García: + + flag: A TRUE/FALSE value indicating if all machines within a given + domain can access the variable. This value is set automatically by + the browser, depending on the value you set for the domain. + + As far as I can see, it is set to true when the cookie says + .domain.com and to false when the domain is complete www.domain.com + */ + co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */ + break; + case 2: + /* It turns out, that sometimes the file format allows the path + field to remain not filled in, we try to detect this and work + around it! Andrés García made us aware of this... */ + if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { + /* only if the path doesn't look like a boolean option! */ + co->path = strdup(ptr); + if(!co->path) + badcookie = TRUE; + break; + } + /* this doesn't look like a path, make one up! */ + co->path = strdup("/"); + if(!co->path) + badcookie = TRUE; + fields++; /* add a field and fall down to secure */ + /* FALLTHROUGH */ + case 3: + co->secure = (bool)strequal(ptr, "TRUE"); + break; + case 4: + co->expires = curlx_strtoofft(ptr, NULL, 10); + break; + case 5: + co->name = strdup(ptr); + if(!co->name) + badcookie = TRUE; + break; + case 6: + co->value = strdup(ptr); + if(!co->value) + badcookie = TRUE; + break; + } + } + if(6 == fields) { + /* we got a cookie with blank contents, fix it */ + co->value = strdup(""); + if(!co->value) + badcookie = TRUE; + else + fields++; + } + + if(!badcookie && (7 != fields)) + /* we did not find the sufficient number of fields */ + badcookie = TRUE; + + if(badcookie) { + freecookie(co); + return NULL; + } + + } + + if(!c->running && /* read from a file */ + c->newsession && /* clean session cookies */ + !co->expires) { /* this is a session cookie since it doesn't expire! */ + freecookie(co); + return NULL; + } + + co->livecookie = c->running; + + /* now, we have parsed the incoming line, we must now check if this + superceeds an already existing cookie, which it may if the previous have + the same domain and path as this */ + + clist = c->cookies; + replace_old = FALSE; + while(clist) { + if(strequal(clist->name, co->name)) { + /* the names are identical */ + + if(clist->domain && co->domain) { + if(strequal(clist->domain, co->domain)) + /* The domains are identical */ + replace_old=TRUE; + } + else if(!clist->domain && !co->domain) + replace_old = TRUE; + + if(replace_old) { + /* the domains were identical */ + + if(clist->path && co->path) { + if(strequal(clist->path, co->path)) { + replace_old = TRUE; + } + else + replace_old = FALSE; + } + else if(!clist->path && !co->path) + replace_old = TRUE; + else + replace_old = FALSE; + + } + + 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 isn't "live" and thus only read from a file. We let + live cookies stay alive */ + + /* Free the newcomer and get out of here! */ + freecookie(co); + return NULL; + } + + if(replace_old) { + co->next = clist->next; /* get the next-pointer first */ + + /* then free all the old pointers */ + if(clist->name) + free(clist->name); + if(clist->value) + free(clist->value); + if(clist->domain) + free(clist->domain); + if(clist->path) + free(clist->path); + if(clist->expirestr) + free(clist->expirestr); + + if(clist->version) + free(clist->version); + if(clist->maxage) + free(clist->maxage); + + *clist = *co; /* then store all the new data */ + + free(co); /* free the newly alloced memory */ + co = clist; /* point to the previous struct instead */ + + /* We have replaced a cookie, now skip the rest of the list but + make sure the 'lastc' pointer is properly set */ + do { + lastc = clist; + clist = clist->next; + } while(clist); + break; + } + } + lastc = clist; + clist = clist->next; + } + + 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 %d\n", + replace_old?"Replaced":"Added", co->name, co->value, + co->domain, co->path, co->expires); + + if(!replace_old) { + /* then make the last item point on this new one */ + if(lastc) + lastc->next = co; + else + c->cookies = co; + } + + c->numcookies++; /* one more cookie in the jar */ + return co; +} + +/***************************************************************************** + * + * Curl_cookie_init() + * + * Inits a cookie struct to read data from a local file. This is always + * called before any cookies are set. File may be NULL. + * + * If 'newsession' is TRUE, discard all "session cookies" on read from file. + * + ****************************************************************************/ +struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, + char *file, + struct CookieInfo *inc, + bool newsession) +{ + struct CookieInfo *c; + FILE *fp; + bool fromfile=TRUE; + + if(NULL == inc) { + /* we didn't get a struct, create one */ + c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo)); + if(!c) + return NULL; /* failed to get memory */ + c->filename = strdup(file?file:"none"); /* copy the name just in case */ + } + else { + /* we got an already existing one, use that */ + c = inc; + } + c->running = FALSE; /* this is not running, this is init */ + + if(file && strequal(file, "-")) { + fp = stdin; + fromfile=FALSE; + } + else if(file && !*file) { + /* points to a "" string */ + fp = NULL; + } + else + fp = file?fopen(file, "r"):NULL; + + c->newsession = newsession; /* new session? */ + + if(fp) { + char *lineptr; + bool headerline; + + char *line = (char *)malloc(MAX_COOKIE_LINE); + if(line) { + while(fgets(line, MAX_COOKIE_LINE, fp)) { + if(checkprefix("Set-Cookie:", line)) { + /* This is a cookie line, get it! */ + lineptr=&line[11]; + headerline=TRUE; + } + else { + lineptr=line; + headerline=FALSE; + } + while(*lineptr && my_isspace(*lineptr)) + lineptr++; + + Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); + } + free(line); /* free the line buffer */ + } + if(fromfile) + fclose(fp); + } + + c->running = TRUE; /* now, we're running */ + + return c; +} + +/***************************************************************************** + * + * Curl_cookie_getlist() + * + * For a given host and path, return a linked list of cookies that the + * client 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 haven't expired. + * + ****************************************************************************/ + +struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, + char *host, char *path, bool secure) +{ + struct Cookie *newco; + struct Cookie *co; + time_t now = time(NULL); + struct Cookie *mainco=NULL; + + if(!c || !c->cookies) + return NULL; /* no cookie struct or no cookies in the struct */ + + co = c->cookies; + + while(co) { + /* only process this cookie if it is not expired or had no expire + date AND that if the cookie requires we're secure we must only + continue if we are! */ + if( (co->expires<=0 || (co->expires> now)) && + (co->secure?secure:TRUE) ) { + + /* now check if the domain is correct */ + if(!co->domain || + (co->tailmatch && tailmatch(co->domain, host)) || + (!co->tailmatch && strequal(host, co->domain)) ) { + /* the right part of the host matches the domain stuff in the + cookie data */ + + /* now check the left part of the path with the cookies path + requirement */ + if(!co->path || + /* not using checkprefix() because matching should be + case-sensitive */ + !strncmp(co->path, path, strlen(co->path)) ) { + + /* and now, we know this is a match and we should create an + entry for the return-linked-list */ + + newco = (struct Cookie *)malloc(sizeof(struct Cookie)); + if(newco) { + /* first, copy the whole source cookie: */ + memcpy(newco, co, sizeof(struct Cookie)); + + /* then modify our next */ + newco->next = mainco; + + /* point the main to us */ + mainco = newco; + } + else { + /* failure, clear up the allocated chain and return NULL */ + while(mainco) { + co = mainco->next; + free(mainco); + mainco = co; + } + + return NULL; + } + } + } + } + co = co->next; + } + + return mainco; /* return the new list */ +} + +/***************************************************************************** + * + * Curl_cookie_clearall() + * + * Clear all existing cookies and reset the counter. + * + ****************************************************************************/ +void Curl_cookie_clearall(struct CookieInfo *cookies) +{ + if(cookies) { + Curl_cookie_freelist(cookies->cookies); + cookies->cookies = NULL; + cookies->numcookies = 0; + } +} + +/***************************************************************************** + * + * Curl_cookie_freelist() + * + * Free a list of cookies previously returned by Curl_cookie_getlist(); + * + ****************************************************************************/ + +void Curl_cookie_freelist(struct Cookie *co) +{ + struct Cookie *next; + if(co) { + while(co) { + next = co->next; + free(co); /* we only free the struct since the "members" are all + just copied! */ + co = next; + } + } +} + + +/***************************************************************************** + * + * Curl_cookie_clearsess() + * + * Free all session cookies in the cookies list. + * + ****************************************************************************/ +void Curl_cookie_clearsess(struct CookieInfo *cookies) +{ + struct Cookie *first, *curr, *next, *prev = NULL; + + if(!cookies->cookies) + return; + + first = curr = prev = cookies->cookies; + + for(; curr; curr = next) { + next = curr->next; + if(!curr->expires) { + if(first == curr) + first = next; + + if(prev == curr) + prev = next; + else + prev->next = next; + + free(curr); + cookies->numcookies--; + } + else + prev = curr; + } + + cookies->cookies = first; +} + + +/***************************************************************************** + * + * Curl_cookie_cleanup() + * + * Free a "cookie object" previous created with cookie_init(). + * + ****************************************************************************/ +void Curl_cookie_cleanup(struct CookieInfo *c) +{ + struct Cookie *co; + struct Cookie *next; + if(c) { + if(c->filename) + free(c->filename); + co = c->cookies; + + while(co) { + next = co->next; + freecookie(co); + co = next; + } + free(c); /* free the base struct as well */ + } +} + +/* get_netscape_format() + * + * Formats a string for Netscape output file, w/o a newline at the end. + * + * Function returns a char * to a formatted line. Has to be free()d +*/ +static char *get_netscape_format(const struct Cookie *co) +{ + return aprintf( + "%s%s\t" /* domain */ + "%s\t" /* tailmatch */ + "%s\t" /* path */ + "%s\t" /* secure */ + "%" FORMAT_OFF_T "\t" /* expires */ + "%s\t" /* name */ + "%s", /* value */ + /* Make sure all domains are prefixed with a dot if they allow + tailmatching. This is Mozilla-style. */ + (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"", + co->domain?co->domain:"unknown", + co->tailmatch?"TRUE":"FALSE", + co->path?co->path:"/", + co->secure?"TRUE":"FALSE", + co->expires, + co->name, + co->value?co->value:""); +} + +/* + * Curl_cookie_output() + * + * Writes all internally known cookies to the specified file. Specify + * "-" as file name to write to stdout. + * + * The function returns non-zero on write failure. + */ +int Curl_cookie_output(struct CookieInfo *c, char *dumphere) +{ + struct Cookie *co; + FILE *out; + bool use_stdout=FALSE; + + if((NULL == c) || (0 == c->numcookies)) + /* If there are no known cookies, we don't write or even create any + destination file */ + return 0; + + if(strequal("-", dumphere)) { + /* use stdout */ + out = stdout; + use_stdout=TRUE; + } + else { + out = fopen(dumphere, "w"); + if(!out) + return 1; /* failure */ + } + + if(c) { + char *format_ptr; + + fputs("# Netscape HTTP Cookie File\n" + "# http://curlm.haxx.se/rfc/cookie_spec.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n\n", + out); + co = c->cookies; + + while(co) { + format_ptr = get_netscape_format(co); + if (format_ptr == NULL) { + fprintf(out, "#\n# Fatal libcurl error\n"); + if(!use_stdout) + fclose(out); + return 1; + } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); + co=co->next; + } + } + + if(!use_stdout) + fclose(out); + + return 0; +} + +struct curl_slist *Curl_cookie_list(struct SessionHandle *data) +{ + struct curl_slist *list = NULL; + struct curl_slist *beg; + struct Cookie *c; + char *line; + + if ((data->cookies == NULL) || + (data->cookies->numcookies == 0)) + return NULL; + + c = data->cookies->cookies; + + beg = list; + while (c) { + /* fill the list with _all_ the cookies we know */ + line = get_netscape_format(c); + if (line == NULL) { + /* get_netscape_format returns null only if we run out of memory */ + + curl_slist_free_all(beg); /* free some memory */ + return NULL; + } + list = curl_slist_append(list, line); + free(line); + c = c->next; + } + + return list; +} + +#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h new file mode 100644 index 0000000..57c3acb --- /dev/null +++ b/Utilities/cmcurl/lib/cookie.h @@ -0,0 +1,107 @@ +#ifndef __COOKIE_H +#define __COOKIE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include +#if defined(WIN32) +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#endif +#endif + +#include + +struct Cookie { + struct Cookie *next; /* next in the chain */ + char *name; /* = value */ + char *value; /* name = */ + char *path; /* path = */ + char *domain; /* domain = */ + curl_off_t expires; /* expires = */ + char *expirestr; /* the plain text version */ + bool tailmatch; /* weather we do tail-matchning of the domain name */ + + /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ + char *version; /* Version = */ + char *maxage; /* Max-Age = */ + + bool secure; /* whether the 'secure' keyword was used */ + bool livecookie; /* updated from a server, not a stored file */ +}; + +struct CookieInfo { + /* linked list of cookies we know of */ + struct Cookie *cookies; + + char *filename; /* file we read from/write to */ + bool running; /* state info, for cookie adding information */ + long numcookies; /* number of cookies in the "jar" */ + bool newsession; /* new session, discard session cookies on load */ +}; + +/* This is the maximum line length we accept for a cookie line. RFC 2109 + section 6.3 says: + + "at least 4096 bytes per cookie (as measured by the size of the characters + that comprise the cookie non-terminal in the syntax description of the + Set-Cookie header)" + +*/ +#define MAX_COOKIE_LINE 5000 +#define MAX_COOKIE_LINE_TXT "4999" + +/* This is the maximum length of a cookie name we deal with: */ +#define MAX_NAME 1024 +#define MAX_NAME_TXT "1023" + +struct SessionHandle; +/* + * Add a cookie to the internal list of cookies. The domain and path arguments + * are only used if the header boolean is TRUE. + */ + +struct Cookie *Curl_cookie_add(struct SessionHandle *data, + struct CookieInfo *, bool header, char *line, + char *domain, char *path); + +struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, + char *, struct CookieInfo *, bool); +struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool); +void Curl_cookie_freelist(struct Cookie *); +void Curl_cookie_clearall(struct CookieInfo *cookies); +void Curl_cookie_clearsess(struct CookieInfo *cookies); +void Curl_cookie_cleanup(struct CookieInfo *); +int Curl_cookie_output(struct CookieInfo *, char *); + +#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) +#define Curl_cookie_list(x) NULL +#define Curl_cookie_loadfiles(x) do { } while (0) +#else +struct curl_slist *Curl_cookie_list(struct SessionHandle *data); +void Curl_cookie_loadfiles(struct SessionHandle *data); +#endif + +#endif diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h new file mode 100644 index 0000000..26948d3 --- /dev/null +++ b/Utilities/cmcurl/lib/curlx.h @@ -0,0 +1,107 @@ +#ifndef __CURLX_H +#define __CURLX_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * Defines protos and includes all header files that provide the curlx_* + * functions. The curlx_* functions are not part of the libcurl API, but are + * stand-alone functions whose sources can be built and linked by apps if need + * be. + */ + +#include +/* 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 "strequal.h" +/* "strequal.h" provides the strequal protos */ + +#include "strtoofft.h" +/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a + curl_off_t number from a given string. +*/ + +#include "timeval.h" +/* + "timeval.h" sets up a 'struct timeval' even for platforms that otherwise + don't have one and has protos for these functions: + + curlx_tvnow() + curlx_tvdiff() + curlx_tvdiff_secs() +*/ + +/* Now setup curlx_ * names for the functions that are to become curlx_ and + be removed from a future libcurl official API: + curlx_getenv + curlx_mprintf (and its variations) + curlx_strequal + curlx_strnequal + +*/ + +#define curlx_getenv curl_getenv +#define curlx_strequal curl_strequal +#define curlx_strnequal curl_strnequal +#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 transparant and + easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE + is set. */ +# undef printf +# undef fprintf +# undef sprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf + +# define printf curlx_mprintf +# define fprintf curlx_mfprintf +# define sprintf curlx_msprintf +# define snprintf curlx_msnprintf +# define vprintf curlx_mvprintf +# define vfprintf curlx_mvfprintf +# define vsprintf curlx_mvsprintf +# define vsnprintf curlx_mvsnprintf +# define aprintf curlx_maprintf +# define vaprintf curlx_mvaprintf +#endif /* ENABLE_CURLX_PRINTF */ + +#endif /* __CURLX_H */ diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c new file mode 100644 index 0000000..d6443f4 --- /dev/null +++ b/Utilities/cmcurl/lib/dict.c @@ -0,0 +1,280 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_DICT + +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef WIN32 +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + + +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" + +#include "progress.h" +#include "strequal.h" +#include "dict.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +static char *unescape_word(struct SessionHandle *data, char *inp) +{ + char *newp; + char *dictp; + char *ptr; + int len; + unsigned char byte; + int olen=0; + + newp = curl_easy_unescape(data, inp, 0, &len); + if(!newp) + return NULL; + + dictp = malloc(len*2 + 1); /* add one for terminating zero */ + if(dictp) { + /* According to RFC2229 section 2.2, these letters need to be escaped with + \[letter] */ + for(ptr = newp; + (byte = (unsigned char)*ptr) != 0; + ptr++) { + if ((byte <= 32) || (byte == 127) || + (byte == '\'') || (byte == '\"') || (byte == '\\')) { + dictp[olen++] = '\\'; + } + dictp[olen++] = byte; + } + dictp[olen]=0; + + free(newp); + } + return dictp; +} + +CURLcode Curl_dict(struct connectdata *conn, bool *done) +{ + char *word; + char *eword; + char *ppath; + char *database = NULL; + char *strategy = NULL; + char *nthdef = NULL; /* This is not part of the protocol, but required + by RFC 2229 */ + CURLcode result=CURLE_OK; + struct SessionHandle *data=conn->data; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + + char *path = data->reqdata.path; + curl_off_t *bytecount = &data->reqdata.keep.bytecount; + + *done = TRUE; /* unconditionally */ + + if(conn->bits.user_passwd) { + /* AUTH is missing */ + } + + if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || + strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || + strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + + word = strchr(path, ':'); + if (word) { + word++; + database = strchr(word, ':'); + if (database) { + *database++ = (char)0; + strategy = strchr(database, ':'); + if (strategy) { + *strategy++ = (char)0; + nthdef = strchr(strategy, ':'); + if (nthdef) { + *nthdef++ = (char)0; + } + } + } + } + + if ((word == NULL) || (*word == (char)0)) { + failf(data, "lookup word is missing"); + } + if ((database == NULL) || (*database == (char)0)) { + database = (char *)"!"; + } + if ((strategy == NULL) || (*strategy == (char)0)) { + strategy = (char *)"."; + } + + eword = unescape_word(data, word); + if(!eword) + return CURLE_OUT_OF_MEMORY; + + result = Curl_sendf(sockfd, conn, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" + "MATCH " + "%s " /* database */ + "%s " /* strategy */ + "%s\r\n" /* word */ + "QUIT\r\n", + + database, + strategy, + eword + ); + + free(eword); + + if(result) + failf(data, "Failed sending DICT request"); + else + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, + -1, NULL); /* no upload */ + if(result) + return result; + } + else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || + strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || + strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + + word = strchr(path, ':'); + if (word) { + word++; + database = strchr(word, ':'); + if (database) { + *database++ = (char)0; + nthdef = strchr(database, ':'); + if (nthdef) { + *nthdef++ = (char)0; + } + } + } + + if ((word == NULL) || (*word == (char)0)) { + failf(data, "lookup word is missing"); + } + if ((database == NULL) || (*database == (char)0)) { + database = (char *)"!"; + } + + eword = unescape_word(data, word); + if(!eword) + return CURLE_OUT_OF_MEMORY; + + result = Curl_sendf(sockfd, conn, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" + "DEFINE " + "%s " /* database */ + "%s\r\n" /* word */ + "QUIT\r\n", + database, + eword); + + free(eword); + + if(result) + failf(data, "Failed sending DICT request"); + else + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, + -1, NULL); /* no upload */ + + if(result) + return result; + + } + else { + + ppath = strchr(path, '/'); + if (ppath) { + int i; + + ppath++; + for (i = 0; ppath[i]; i++) { + if (ppath[i] == ':') + ppath[i] = ' '; + } + result = Curl_sendf(sockfd, conn, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" + "%s\r\n" + "QUIT\r\n", ppath); + if(result) + failf(data, "Failed sending DICT request"); + else + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, + -1, NULL); + if(result) + return result; + } + } + + return CURLE_OK; +} +#endif /*CURL_DISABLE_DICT*/ diff --git a/Utilities/cmcurl/lib/dict.h b/Utilities/cmcurl/lib/dict.h new file mode 100644 index 0000000..d3da193 --- /dev/null +++ b/Utilities/cmcurl/lib/dict.h @@ -0,0 +1,30 @@ +#ifndef __DICT_H +#define __DICT_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_DICT +CURLcode Curl_dict(struct connectdata *conn, bool *done); +CURLcode Curl_dict_done(struct connectdata *conn); +#endif +#endif diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c new file mode 100644 index 0000000..209d1c3 --- /dev/null +++ b/Utilities/cmcurl/lib/easy.c @@ -0,0 +1,895 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#include + +#include "strequal.h" + +#ifdef WIN32 +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#endif /* WIN32 ... */ + +#include "urldata.h" +#include +#include "transfer.h" +#include "sslgen.h" +#include "url.h" +#include "getinfo.h" +#include "hostip.h" +#include "share.h" +#include "strdup.h" +#include "memory.h" +#include "progress.h" +#include "easyif.h" +#include "sendf.h" /* for failf function prototype */ +#include + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) +#include +/* set default codesets for iconv */ +#ifndef CURL_ICONV_CODESET_OF_NETWORK +#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" +#endif +#ifndef CURL_ICONV_CODESET_FOR_UTF8 +#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" +#endif +#define ICONV_ERROR (size_t)-1 +#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifdef USE_WINSOCK +/* win32_cleanup() is for win32 socket cleanup functionality, the opposite + of win32_init() */ +static void win32_cleanup(void) +{ + WSACleanup(); +} + +/* win32_init() performs win32 socket initialization to properly setup the + stack to allow networking */ +static CURLcode win32_init(void) +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + +#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2) + Error IPV6_requires_winsock2 +#endif + + wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); + + err = WSAStartup(wVersionRequested, &wsaData); + + if (err != 0) + /* Tell the user that we couldn't find a useable */ + /* winsock.dll. */ + return CURLE_FAILED_INIT; + + /* Confirm that the Windows Sockets DLL supports what we need.*/ + /* Note that if the DLL supports versions greater */ + /* than wVersionRequested, it will still return */ + /* wVersionRequested in wVersion. wHighVersion contains the */ + /* highest supported version. */ + + if ( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || + HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { + /* Tell the user that we couldn't find a useable */ + + /* winsock.dll. */ + WSACleanup(); + return CURLE_FAILED_INIT; + } + /* The Windows Sockets DLL is acceptable. Proceed. */ + return CURLE_OK; +} + +#else +/* These functions exist merely to prevent compiler warnings */ +static CURLcode win32_init(void) { return CURLE_OK; } +static void win32_cleanup(void) { } +#endif + +#ifdef USE_LIBIDN +/* + * Initialise use of IDNA library. + * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for + * idna_to_ascii_lz(). + */ +static void idna_init (void) +{ +#ifdef WIN32 + char buf[60]; + UINT cp = GetACP(); + + if (!getenv("CHARSET") && cp > 0) { + snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp); + putenv(buf); + } +#else + /* to do? */ +#endif +} +#endif /* USE_LIBIDN */ + +/* true globals -- for curl_global_init() and curl_global_cleanup() */ +static unsigned int initialized; +static long init_flags; + +/* + * strdup (and other memory functions) is redefined in complicated + * ways, but at this point it must be defined as the system-supplied strdup + * so the callback pointer is initialized correctly. + */ +#if defined(_WIN32_WCE) +#define system_strdup _strdup +#elif !defined(HAVE_STRDUP) +#define system_strdup curlx_strdup +#else +#define system_strdup strdup +#endif + +/* + * If a memory-using function (like curl_getenv) is used before + * curl_global_init() is called, we need to have these pointers set already. + */ + +curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; +curl_free_callback Curl_cfree = (curl_free_callback)free; +curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; +curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; +curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; + +/** + * curl_global_init() globally initializes cURL given a bitwise set of the + * different features of what to initialize. + */ +CURLcode curl_global_init(long flags) +{ + if (initialized++) + return CURLE_OK; + + /* Setup the default memory functions here (again) */ + Curl_cmalloc = (curl_malloc_callback)malloc; + Curl_cfree = (curl_free_callback)free; + Curl_crealloc = (curl_realloc_callback)realloc; + Curl_cstrdup = (curl_strdup_callback)system_strdup; + Curl_ccalloc = (curl_calloc_callback)calloc; + + if (flags & CURL_GLOBAL_SSL) + if (!Curl_ssl_init()) + return CURLE_FAILED_INIT; + + if (flags & CURL_GLOBAL_WIN32) + if (win32_init() != CURLE_OK) + return CURLE_FAILED_INIT; + +#ifdef _AMIGASF + if(!amiga_init()) + return CURLE_FAILED_INIT; +#endif + +#ifdef USE_LIBIDN + idna_init(); +#endif + + init_flags = flags; + + return CURLE_OK; +} + +/* + * curl_global_init_mem() globally initializes cURL and also registers the + * user provided callback routines. + */ +CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, + curl_free_callback f, curl_realloc_callback r, + curl_strdup_callback s, curl_calloc_callback c) +{ + CURLcode code = CURLE_OK; + + /* Invalid input, return immediately */ + if (!m || !f || !r || !s || !c) + return CURLE_FAILED_INIT; + + /* Already initialized, don't do it again */ + if ( initialized ) + return CURLE_OK; + + /* Call the actual init function first */ + code = curl_global_init(flags); + if (code == CURLE_OK) { + Curl_cmalloc = m; + Curl_cfree = f; + Curl_cstrdup = s; + Curl_crealloc = r; + Curl_ccalloc = c; + } + + return code; +} + +/** + * curl_global_cleanup() globally cleanups cURL, uses the value of + * "init_flags" to determine what needs to be cleaned up and what doesn't. + */ +void curl_global_cleanup(void) +{ + if (!initialized) + return; + + if (--initialized) + return; + + Curl_global_host_cache_dtor(); + + if (init_flags & CURL_GLOBAL_SSL) + Curl_ssl_cleanup(); + + if (init_flags & CURL_GLOBAL_WIN32) + win32_cleanup(); + +#ifdef _AMIGASF + amiga_cleanup(); +#endif + + init_flags = 0; +} + +/* + * curl_easy_init() is the external interface to alloc, setup and init an + * easy handle that is returned. If anything goes wrong, NULL is returned. + */ +CURL *curl_easy_init(void) +{ + CURLcode res; + struct SessionHandle *data; + + /* Make sure we inited the global SSL stuff */ + if (!initialized) { + res = curl_global_init(CURL_GLOBAL_DEFAULT); + if(res) + /* something in the global init failed, return nothing */ + return NULL; + } + + /* We use curl_open() with undefined URL so far */ + res = Curl_open(&data); + if(res != CURLE_OK) + return NULL; + + return data; +} + +/* + * curl_easy_setopt() is the external interface for setting options on an + * easy handle. + */ + +CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) +{ + va_list arg; + struct SessionHandle *data = curl; + CURLcode ret; + + if(!curl) + return CURLE_BAD_FUNCTION_ARGUMENT; + + va_start(arg, tag); + + ret = Curl_setopt(data, tag, arg); + + va_end(arg); + return ret; +} + +#ifdef CURL_MULTIEASY +/*************************************************************************** + * This function is still only for testing purposes. It makes a great way + * to run the full test suite on the multi interface instead of the easy one. + *************************************************************************** + * + * The *new* curl_easy_perform() is the external interface that performs a + * transfer previously setup. + * + * Wrapper-function that: creates a multi handle, adds the easy handle to it, + * runs curl_multi_perform() until the transfer is done, then detaches the + * easy handle, destroys the multi handle and returns the easy handle's return + * code. This will make everything internally use and assume multi interface. + */ +CURLcode curl_easy_perform(CURL *easy) +{ + CURLM *multi; + CURLMcode mcode; + CURLcode code = CURLE_OK; + int still_running; + struct timeval timeout; + int rc; + CURLMsg *msg; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd; + + if(!easy) + return CURLE_BAD_FUNCTION_ARGUMENT; + + multi = curl_multi_init(); + if(!multi) + return CURLE_OUT_OF_MEMORY; + + mcode = curl_multi_add_handle(multi, easy); + if(mcode) { + curl_multi_cleanup(multi); + return CURLE_FAILED_INIT; + } + + /* we start some action by calling perform right away */ + + do { + while(CURLM_CALL_MULTI_PERFORM == + curl_multi_perform(multi, &still_running)); + + if(!still_running) + break; + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + /* timeout once per second */ + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + /* get file descriptors from the transfers */ + curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); + + rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + if(rc == -1) + /* select error */ + break; + + /* timeout or data to send/receive => loop! */ + } while(still_running); + + msg = curl_multi_info_read(multi, &rc); + if(msg) + code = msg->data.result; + + mcode = curl_multi_remove_handle(multi, easy); + /* what to do if it fails? */ + + mcode = curl_multi_cleanup(multi); + /* what to do if it fails? */ + + return code; +} +#else +/* + * curl_easy_perform() is the external interface that performs a transfer + * previously setup. + */ +CURLcode curl_easy_perform(CURL *curl) +{ + struct SessionHandle *data = (struct SessionHandle *)curl; + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if ( ! (data->share && data->share->hostcache) ) { + + if (Curl_global_host_cache_use(data) && + (data->dns.hostcachetype != HCACHE_GLOBAL)) { + if (data->dns.hostcachetype == HCACHE_PRIVATE) + Curl_hash_destroy(data->dns.hostcache); + data->dns.hostcache = Curl_global_host_cache_get(); + data->dns.hostcachetype = HCACHE_GLOBAL; + } + + if (!data->dns.hostcache) { + data->dns.hostcachetype = HCACHE_PRIVATE; + data->dns.hostcache = Curl_mk_dnscache(); + + if(!data->dns.hostcache) + /* While we possibly could survive and do good without a host cache, + the fact that creating it failed indicates that things are truly + screwed up and we should bail out! */ + return CURLE_OUT_OF_MEMORY; + } + + } + + if(!data->state.connc) { + /* oops, no connection cache, make one up */ + data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1); + if(!data->state.connc) + return CURLE_OUT_OF_MEMORY; + } + + return Curl_perform(data); +} +#endif + +/* + * curl_easy_cleanup() is the external interface to cleaning/freeing the given + * easy handle. + */ +void curl_easy_cleanup(CURL *curl) +{ + struct SessionHandle *data = (struct SessionHandle *)curl; + + if(!data) + return; + + Curl_close(data); +} + +/* + * Store a pointed to the multi handle within the easy handle's data struct. + */ +void Curl_easy_addmulti(struct SessionHandle *data, + void *multi) +{ + data->multi = multi; +} + +void Curl_easy_initHandleData(struct SessionHandle *data) +{ + memset(&data->reqdata, 0, sizeof(struct HandleData)); + + data->reqdata.maxdownload = -1; +} + +/* + * curl_easy_getinfo() is an external interface that allows an app to retrieve + * information from a performed transfer and similar. + */ +CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) +{ + va_list arg; + void *paramp; + struct SessionHandle *data = (struct SessionHandle *)curl; + + va_start(arg, info); + paramp = va_arg(arg, void *); + + return Curl_getinfo(data, info, paramp); +} + +/* + * curl_easy_duphandle() is an external interface to allow duplication of a + * given input easy handle. The returned handle will be a new working handle + * with all options set exactly as the input source handle. + */ +CURL *curl_easy_duphandle(CURL *incurl) +{ + bool fail = TRUE; + struct SessionHandle *data=(struct SessionHandle *)incurl; + + struct SessionHandle *outcurl = (struct SessionHandle *) + calloc(sizeof(struct SessionHandle), 1); + + if(NULL == outcurl) + return NULL; /* failure */ + + do { + + /* + * We setup a few buffers we need. We should probably make them + * get setup on-demand in the code, as that would probably decrease + * the likeliness of us forgetting to init a buffer here in the future. + */ + outcurl->state.headerbuff=(char*)malloc(HEADERSIZE); + if(!outcurl->state.headerbuff) { + break; + } + outcurl->state.headersize=HEADERSIZE; + + /* copy all userdefined values */ + outcurl->set = data->set; + + if(data->state.used_interface == Curl_if_multi) + outcurl->state.connc = data->state.connc; + else + outcurl->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1); + + if(!outcurl->state.connc) + break; + + outcurl->state.lastconnect = -1; + + outcurl->progress.flags = data->progress.flags; + outcurl->progress.callback = data->progress.callback; + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(data->cookies) { + /* If cookies are enabled in the parent handle, we enable them + in the clone as well! */ + outcurl->cookies = Curl_cookie_init(data, + data->cookies->filename, + outcurl->cookies, + data->set.cookiesession); + if(!outcurl->cookies) { + break; + } + } +#endif /* CURL_DISABLE_HTTP */ + + /* duplicate all values in 'change' */ + + if(data->change.url) { + outcurl->change.url = strdup(data->change.url); + if(!outcurl->change.url) + break; + outcurl->change.url_alloc = TRUE; + } + + if(data->change.referer) { + outcurl->change.referer = strdup(data->change.referer); + if(!outcurl->change.referer) + break; + outcurl->change.referer_alloc = TRUE; + } + +#ifdef USE_ARES + /* If we use ares, we setup a new ares channel for the new handle */ + if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel)) + break; +#endif + +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) + outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK); + outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST); + outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8); +#endif + + Curl_easy_initHandleData(outcurl); + + outcurl->magic = CURLEASY_MAGIC_NUMBER; + + fail = FALSE; /* we reach this point and thus we are OK */ + + } while(0); + + if(fail) { + if(outcurl) { + if(outcurl->state.connc->type == CONNCACHE_PRIVATE) + Curl_rm_connc(outcurl->state.connc); + if(outcurl->state.headerbuff) + free(outcurl->state.headerbuff); + if(outcurl->change.url) + free(outcurl->change.url); + if(outcurl->change.referer) + free(outcurl->change.referer); + free(outcurl); /* free the memory again */ + outcurl = NULL; + } + } + + return outcurl; +} + +/* + * curl_easy_reset() is an external interface that allows an app to re- + * initialize a session handle to the default values. + */ +void curl_easy_reset(CURL *curl) +{ + struct SessionHandle *data = (struct SessionHandle *)curl; + + Curl_safefree(data->reqdata.pathbuffer); + data->reqdata.pathbuffer=NULL; + + Curl_safefree(data->reqdata.proto.generic); + data->reqdata.proto.generic=NULL; + + /* zero out UserDefined data: */ + memset(&data->set, 0, sizeof(struct UserDefined)); + + /* zero out Progress data: */ + memset(&data->progress, 0, sizeof(struct Progress)); + + /* init Handle data */ + Curl_easy_initHandleData(data); + + /* The remainder of these calls have been taken from Curl_open() */ + + data->set.out = stdout; /* default output to stdout */ + data->set.in = stdin; /* default input from stdin */ + data->set.err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + data->set.fwrite = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + data->set.fread = (curl_read_callback)fread; + + data->set.infilesize = -1; /* we don't know any size */ + data->set.postfieldsize = -1; + + data->state.current_speed = -1; /* init to negative == impossible */ + + data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */ + data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + + data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* make libcurl quiet by default: */ + data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + data->progress.flags |= PGRS_HIDE; + + /* Set the default size of the SSL session ID cache */ + data->set.ssl.numsessions = 5; + + data->set.proxyport = 1080; + data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */ + data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + data->set.ssl.verifypeer = TRUE; + data->set.ssl.verifyhost = 2; +#ifdef CURL_CA_BUNDLE + /* This is our preferred CA cert bundle since install time */ + data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; +#endif + + data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ +} + +#ifdef CURL_DOES_CONVERSIONS +/* + * Curl_convert_to_network() is an internal function + * for performing ASCII conversions on non-ASCII platforms. + */ +CURLcode Curl_convert_to_network(struct SessionHandle *data, + char *buffer, size_t length) +{ + CURLcode rc; + + if(data->set.convtonetwork) { + /* use translation callback */ + rc = data->set.convtonetwork(buffer, length); + if(rc != CURLE_OK) { + failf(data, + "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s", + rc, curl_easy_strerror(rc)); + } + return(rc); + } else { +#ifdef HAVE_ICONV + /* do the translation ourselves */ + char *input_ptr, *output_ptr; + size_t in_bytes, out_bytes, rc; + + /* open an iconv conversion descriptor if necessary */ + if(data->outbound_cd == (iconv_t)-1) { + data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST); + if(data->outbound_cd == (iconv_t)-1) { + failf(data, + "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", + CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST, + errno, strerror(errno)); + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if ((rc == ICONV_ERROR) || (in_bytes != 0)) { + failf(data, + "The Curl_convert_to_network iconv call failed with errno %i: %s", + errno, strerror(errno)); + return CURLE_CONV_FAILED; + } +#else + failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required"); + return CURLE_CONV_REQD; +#endif /* HAVE_ICONV */ + } + + return CURLE_OK; +} + +/* + * Curl_convert_from_network() is an internal function + * for performing ASCII conversions on non-ASCII platforms. + */ +CURLcode Curl_convert_from_network(struct SessionHandle *data, + char *buffer, size_t length) +{ + CURLcode rc; + + if(data->set.convfromnetwork) { + /* use translation callback */ + rc = data->set.convfromnetwork(buffer, length); + if(rc != CURLE_OK) { + failf(data, + "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s", + rc, curl_easy_strerror(rc)); + } + return(rc); + } else { +#ifdef HAVE_ICONV + /* do the translation ourselves */ + char *input_ptr, *output_ptr; + size_t in_bytes, out_bytes, rc; + + /* open an iconv conversion descriptor if necessary */ + if(data->inbound_cd == (iconv_t)-1) { + data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK); + if(data->inbound_cd == (iconv_t)-1) { + failf(data, + "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", + CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK, + errno, strerror(errno)); + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if ((rc == ICONV_ERROR) || (in_bytes != 0)) { + failf(data, + "The Curl_convert_from_network iconv call failed with errno %i: %s", + errno, strerror(errno)); + return CURLE_CONV_FAILED; + } +#else + failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required"); + return CURLE_CONV_REQD; +#endif /* HAVE_ICONV */ + } + + return CURLE_OK; +} + +/* + * Curl_convert_from_utf8() is an internal function + * for performing UTF-8 conversions on non-ASCII platforms. + */ +CURLcode Curl_convert_from_utf8(struct SessionHandle *data, + char *buffer, size_t length) +{ + CURLcode rc; + + if(data->set.convfromutf8) { + /* use translation callback */ + rc = data->set.convfromutf8(buffer, length); + if(rc != CURLE_OK) { + failf(data, + "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s", + rc, curl_easy_strerror(rc)); + } + return(rc); + } else { +#ifdef HAVE_ICONV + /* do the translation ourselves */ + char *input_ptr, *output_ptr; + size_t in_bytes, out_bytes, rc; + + /* open an iconv conversion descriptor if necessary */ + if(data->utf8_cd == (iconv_t)-1) { + data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8); + if(data->utf8_cd == (iconv_t)-1) { + failf(data, + "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", + CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8, + errno, strerror(errno)); + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + rc = iconv(data->utf8_cd, (const char**)&input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if ((rc == ICONV_ERROR) || (in_bytes != 0)) { + failf(data, + "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", + errno, strerror(errno)); + return CURLE_CONV_FAILED; + } + if (output_ptr < input_ptr) { + /* null terminate the now shorter output string */ + *output_ptr = 0x00; + } +#else + failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required"); + return CURLE_CONV_REQD; +#endif /* HAVE_ICONV */ + } + + return CURLE_OK; +} + +#endif /* CURL_DOES_CONVERSIONS */ diff --git a/Utilities/cmcurl/lib/easyif.h b/Utilities/cmcurl/lib/easyif.h new file mode 100644 index 0000000..4c0f7e7 --- /dev/null +++ b/Utilities/cmcurl/lib/easyif.h @@ -0,0 +1,40 @@ +#ifndef __EASYIF_H +#define __EASYIF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * Prototypes for library-wide functions provided by easy.c + */ +void Curl_easy_addmulti(struct SessionHandle *data, void *multi); + +void Curl_easy_initHandleData(struct SessionHandle *data); + +CURLcode Curl_convert_to_network(struct SessionHandle *data, + char *buffer, size_t length); +CURLcode Curl_convert_from_network(struct SessionHandle *data, + char *buffer, size_t length); +CURLcode Curl_convert_from_utf8(struct SessionHandle *data, + char *buffer, size_t length); + +#endif /* __EASYIF_H */ diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c new file mode 100644 index 0000000..9552b0f --- /dev/null +++ b/Utilities/cmcurl/lib/escape.c @@ -0,0 +1,181 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* Escape and unescape URL encoding in strings. The functions return a new + * allocated string or NULL if an error occurred. */ + +#include "setup.h" +#include +#include + +#include +#include +#include +#include "memory.h" +/* urldata.h and easyif.h are included for Curl_convert_... prototypes */ +#include "urldata.h" +#include "easyif.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +/* for ABI-compatibility with previous versions */ +char *curl_escape(const char *string, int inlength) +{ + return curl_easy_escape(NULL, string, inlength); +} + +/* for ABI-compatibility with previous versions */ +char *curl_unescape(const char *string, int length) +{ + return curl_easy_unescape(NULL, string, length, NULL); +} + +char *curl_easy_escape(CURL *handle, const char *string, int inlength) +{ + size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; + char *ns; + char *testing_ptr = NULL; + unsigned char in; + size_t newlen = alloc; + int strindex=0; + size_t length; + +#ifndef CURL_DOES_CONVERSIONS + /* avoid compiler warnings */ + (void)handle; +#endif + ns = malloc(alloc); + if(!ns) + return NULL; + + length = alloc-1; + while(length--) { + in = *string; + if(!(in >= 'a' && in <= 'z') && + !(in >= 'A' && in <= 'Z') && + !(in >= '0' && in <= '9')) { + /* encode it */ + newlen += 2; /* the size grows with two, since this'll become a %XX */ + if(newlen > alloc) { + alloc *= 2; + testing_ptr = realloc(ns, alloc); + if(!testing_ptr) { + free( ns ); + return NULL; + } + else { + ns = testing_ptr; + } + } + +#ifdef CURL_DOES_CONVERSIONS +/* escape sequences are always in ASCII so convert them on non-ASCII hosts */ + if (!handle || + (Curl_convert_to_network(handle, &in, 1) != CURLE_OK)) { + /* Curl_convert_to_network calls failf if unsuccessful */ + free(ns); + return NULL; + } +#endif /* CURL_DOES_CONVERSIONS */ + + snprintf(&ns[strindex], 4, "%%%02X", in); + + strindex+=3; + } + else { + /* just copy this */ + ns[strindex++]=in; + } + string++; + } + ns[strindex]=0; /* terminate it */ + return ns; +} + +char *curl_easy_unescape(CURL *handle, const char *string, int length, + int *olen) +{ + int alloc = (length?length:(int)strlen(string))+1; + char *ns = malloc(alloc); + unsigned char in; + int strindex=0; + long hex; + +#ifndef CURL_DOES_CONVERSIONS + /* avoid compiler warnings */ + (void)handle; +#endif + if( !ns ) + return NULL; + + while(--alloc > 0) { + in = *string; + if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { + /* this is two hexadecimal digits following a '%' */ + char hexstr[3]; + char *ptr; + hexstr[0] = string[1]; + hexstr[1] = string[2]; + hexstr[2] = 0; + + hex = strtol(hexstr, &ptr, 16); + + in = (unsigned char)hex; /* this long is never bigger than 255 anyway */ + +#ifdef CURL_DOES_CONVERSIONS +/* escape sequences are always in ASCII so convert them on non-ASCII hosts */ + if (!handle || + (Curl_convert_from_network(handle, &in, 1) != CURLE_OK)) { + /* Curl_convert_from_network calls failf if unsuccessful */ + free(ns); + return NULL; + } +#endif /* CURL_DOES_CONVERSIONS */ + + string+=2; + alloc-=2; + } + + ns[strindex++] = in; + string++; + } + ns[strindex]=0; /* terminate it */ + + if(olen) + /* store output size */ + *olen = strindex; + return ns; +} + +/* For operating systems/environments that use different malloc/free + ssystems for the app and for this library, we provide a free that uses + the library's memory system */ +void curl_free(void *p) +{ + if(p) + free(p); +} diff --git a/Utilities/cmcurl/lib/escape.h b/Utilities/cmcurl/lib/escape.h new file mode 100644 index 0000000..a0a0209 --- /dev/null +++ b/Utilities/cmcurl/lib/escape.h @@ -0,0 +1,30 @@ +#ifndef __ESCAPE_H +#define __ESCAPE_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +/* Escape and unescape URL encoding in strings. The functions return a new + * allocated string or NULL if an error occurred. */ + + +#endif diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c new file mode 100644 index 0000000..b247a77 --- /dev/null +++ b/Utilities/cmcurl/lib/file.c @@ -0,0 +1,407 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_FILE +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef WIN32 +#include +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#endif + +#include "urldata.h" +#include +#include "progress.h" +#include "sendf.h" +#include "escape.h" +#include "file.h" +#include "speedcheck.h" +#include "getinfo.h" +#include "transfer.h" +#include "url.h" +#include "memory.h" +#include "parsedate.h" /* for the week day and month names */ + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to + * do protocol-specific actions at connect-time. We emulate a + * connect-then-transfer protocol and "connect" to the file here + */ +CURLcode Curl_file_connect(struct connectdata *conn) +{ + char *real_path = curl_easy_unescape(conn->data, conn->data->reqdata.path, 0, NULL); + struct FILEPROTO *file; + int fd; +#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) + int i; + char *actual_path; +#endif + + if(!real_path) + return CURLE_OUT_OF_MEMORY; + + file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1); + if(!file) { + free(real_path); + return CURLE_OUT_OF_MEMORY; + } + + if (conn->data->reqdata.proto.file) { + free(conn->data->reqdata.proto.file); + } + + conn->data->reqdata.proto.file = file; + +#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) + /* 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 + slash in all cases, paths without drive letters end up + 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 + with a drive letter. + */ + actual_path = real_path; + if ((actual_path[0] == '/') && + actual_path[1] && + (actual_path[2] == ':' || actual_path[2] == '|')) + { + actual_path[2] = ':'; + actual_path++; + } + + /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ + for (i=0; actual_path[i] != '\0'; ++i) + if (actual_path[i] == '/') + actual_path[i] = '\\'; + + fd = open(actual_path, O_RDONLY | O_BINARY); /* no CR/LF translation! */ + file->path = actual_path; +#else + fd = open(real_path, O_RDONLY); + file->path = real_path; +#endif + file->freepath = real_path; /* free this when done */ + + file->fd = fd; + if(!conn->data->set.upload && (fd == -1)) { + failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path); + Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); + return CURLE_FILE_COULDNT_READ_FILE; + } + + return CURLE_OK; +} + +CURLcode Curl_file_done(struct connectdata *conn, + CURLcode status, bool premature) +{ + struct FILEPROTO *file = conn->data->reqdata.proto.file; + (void)status; /* not used */ + (void)premature; /* not used */ + Curl_safefree(file->freepath); + + if(file->fd != -1) + close(file->fd); + + return CURLE_OK; +} + +#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +static CURLcode file_upload(struct connectdata *conn) +{ + struct FILEPROTO *file = conn->data->reqdata.proto.file; + char *dir = strchr(file->path, DIRSEP); + FILE *fp; + CURLcode res=CURLE_OK; + struct SessionHandle *data = conn->data; + char *buf = data->state.buffer; + size_t nread; + size_t nwrite; + curl_off_t bytecount = 0; + struct timeval now = Curl_tvnow(); + + /* + * Since FILE: doesn't do the full init, we need to provide some extra + * assignments here. + */ + conn->fread = data->set.fread; + conn->fread_in = data->set.in; + conn->data->reqdata.upload_fromhere = buf; + + if(!dir) + return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ + + if(!dir[1]) + return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ + + fp = fopen(file->path, "wb"); + if(!fp) { + failf(data, "Can't open %s for writing", file->path); + return CURLE_WRITE_ERROR; + } + + if(-1 != data->set.infilesize) + /* known size of data to "upload" */ + Curl_pgrsSetUploadSize(data, data->set.infilesize); + + while (res == CURLE_OK) { + int readcount; + res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); + if(res) + break; + + if (readcount <= 0) /* fix questionable compare error. curlvms */ + break; + + nread = (size_t)readcount; + + /* write the data to the target */ + nwrite = fwrite(buf, 1, nread, fp); + if(nwrite != nread) { + res = CURLE_SEND_ERROR; + break; + } + + bytecount += nread; + + Curl_pgrsSetUploadCounter(data, bytecount); + + if(Curl_pgrsUpdate(conn)) + res = CURLE_ABORTED_BY_CALLBACK; + else + res = Curl_speedcheck(data, now); + } + if(!res && Curl_pgrsUpdate(conn)) + res = CURLE_ABORTED_BY_CALLBACK; + + fclose(fp); + + return res; +} + +/* + * Curl_file() 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 don't allow select()ing etc on file handles (as + * opposed to sockets) we instead perform the whole do-operation in this + * function. + */ +CURLcode Curl_file(struct connectdata *conn, bool *done) +{ + /* 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 + */ + CURLcode res = CURLE_OK; + struct_stat statbuf; /* struct_stat instead of struct stat just to allow the + Windows version to have a different struct without + having to redefine the simple word 'stat' */ + curl_off_t expected_size=0; + bool fstated=FALSE; + ssize_t nread; + struct SessionHandle *data = conn->data; + char *buf = data->state.buffer; + curl_off_t bytecount = 0; + int fd; + struct timeval now = Curl_tvnow(); + + *done = TRUE; /* unconditionally */ + + Curl_readwrite_init(conn); + Curl_initinfo(data); + Curl_pgrsStartNow(data); + + if(data->set.upload) + return file_upload(conn); + + /* get the fd from the connection phase */ + fd = conn->data->reqdata.proto.file->fd; + + /* VMS: This only works reliable for STREAMLF files */ + if( -1 != fstat(fd, &statbuf)) { + /* we could stat it, then read out the size */ + expected_size = statbuf.st_size; + fstated = TRUE; + } + + /* If we have selected NOBODY and HEADER, it means that we only want file + information. Which for FILE can't be much more than the file size and + date. */ + if(conn->bits.no_body && data->set.include_header && fstated) { + CURLcode result; + snprintf(buf, sizeof(data->state.buffer), + "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(result) + return result; + + result = Curl_client_write(conn, CLIENTWRITE_BOTH, + (char *)"Accept-ranges: bytes\r\n", 0); + if(result) + return result; + + if(fstated) { + struct tm *tm; + time_t clock = (time_t)statbuf.st_mtime; +#ifdef HAVE_GMTIME_R + struct tm buffer; + tm = (struct tm *)gmtime_r(&clock, &buffer); +#else + tm = gmtime(&clock); +#endif + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + snprintf(buf, BUFSIZE-1, + "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); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + } + return result; + } + + if (data->reqdata.resume_from <= expected_size) + expected_size -= data->reqdata.resume_from; + else { + failf(data, "failed to resume file:// transfer"); + return CURLE_BAD_DOWNLOAD_RESUME; + } + + if (fstated && (expected_size == 0)) + return CURLE_OK; + + /* The following is a shortcut implementation of file reading + this is both more efficient than the former call to download() and + it avoids problems with select() and recv() on file descriptors + in Winsock */ + if(fstated) + Curl_pgrsSetDownloadSize(data, expected_size); + + if(data->reqdata.resume_from) { + if(data->reqdata.resume_from != + lseek(fd, data->reqdata.resume_from, SEEK_SET)) + return CURLE_BAD_DOWNLOAD_RESUME; + } + + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + + while (res == CURLE_OK) { + nread = read(fd, buf, BUFSIZE-1); + + if ( nread > 0) + buf[nread] = 0; + + if (nread <= 0) + break; + + bytecount += nread; + + res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); + if(res) + return res; + + Curl_pgrsSetDownloadCounter(data, bytecount); + + if(Curl_pgrsUpdate(conn)) + res = CURLE_ABORTED_BY_CALLBACK; + else + res = Curl_speedcheck(data, now); + } + if(Curl_pgrsUpdate(conn)) + res = CURLE_ABORTED_BY_CALLBACK; + + return res; +} + +#endif diff --git a/Utilities/cmcurl/lib/file.h b/Utilities/cmcurl/lib/file.h new file mode 100644 index 0000000..20a1c4c --- /dev/null +++ b/Utilities/cmcurl/lib/file.h @@ -0,0 +1,31 @@ +#ifndef __FILE_H +#define __FILE_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_FILE +CURLcode Curl_file(struct connectdata *, bool *done); +CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature); +CURLcode Curl_file_connect(struct connectdata *); +#endif +#endif diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c new file mode 100644 index 0000000..f10c6c7 --- /dev/null +++ b/Utilities/cmcurl/lib/formdata.c @@ -0,0 +1,1694 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + Debug the form generator stand-alone by compiling this source file with: + + gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c + + run the 'formdata' executable the output should end with: + All Tests seem to have worked ... + and the following parts should be there: + +Content-Disposition: form-data; name="simple_COPYCONTENTS" +value for simple COPYCONTENTS + +Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE" +Content-Type: image/gif +value for COPYCONTENTS + CONTENTTYPE + +Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH" +vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH +(or you might see P^@RNAME and v^@lue at the start) + +Content-Disposition: form-data; name="simple_PTRCONTENTS" +value for simple PTRCONTENTS + +Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH" +vlue for PTRCONTENTS + CONTENTSLENGTH +(or you might see v^@lue at the start) + +Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE" +Content-Type: text/plain +vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE +(or you might see v^@lue at the start) + +Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h" +Content-Type: text/html +... + +Content-Disposition: form-data; name="FILE1_+_FILE2" +Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz +... +Content-Disposition: attachment; filename="inet_ntoa_r.h" +Content-Type: text/plain +... +Content-Disposition: attachment; filename="Makefile.b32" +Content-Type: text/plain +... + +Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3" +Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1 +... +Content-Disposition: attachment; filename="inet_ntoa_r.h" +Content-Type: text/plain +... +Content-Disposition: attachment; filename="Makefile.b32" +Content-Type: text/plain +... +Content-Disposition: attachment; filename="inet_ntoa_r.h" +Content-Type: text/plain +... + + +Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3" +Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1 +... +Content-Disposition: attachment; filename="inet_ntoa_r.h" +Content-Type: text/plain +... +Content-Disposition: attachment; filename="Makefile.b32" +Content-Type: text/plain +... +Content-Disposition: attachment; filename="inet_ntoa_r.h" +Content-Type: text/plain +... + +Content-Disposition: form-data; name="FILECONTENT" +... + + */ + +#include "setup.h" +#include + +/* Length of the random boundary string. */ +#define BOUNDARY_LENGTH 40 + +#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +#include +#endif +#include "urldata.h" /* for struct SessionHandle */ +#include "easyif.h" /* for Curl_convert_... prototypes */ +#include "formdata.h" +#include "strequal.h" +#include "memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */ + +#ifndef CURL_DISABLE_HTTP + +#if defined(HAVE_BASENAME) && defined(NEED_BASENAME_PROTO) +/* This system has a basename() but no prototype for it! */ +char *basename(char *path); +#endif + +static size_t readfromfile(struct Form *form, char *buffer, size_t size); + +/* What kind of Content-Type to use on un-specified files with unrecognized + extensions. */ +#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream" + +#define FORM_FILE_SEPARATOR ',' +#define FORM_TYPE_SEPARATOR ';' + +/*************************************************************************** + * + * AddHttpPost() + * + * Adds a HttpPost structure to the list, if parent_post is given becomes + * a subpost of parent_post instead of a direct list element. + * + * Returns newly allocated HttpPost on success and NULL if malloc failed. + * + ***************************************************************************/ +static struct curl_httppost * +AddHttpPost(char * name, size_t namelength, + char * value, size_t contentslength, + char * buffer, size_t bufferlength, + char *contenttype, + long flags, + struct curl_slist* contentHeader, + char *showfilename, + struct curl_httppost *parent_post, + struct curl_httppost **httppost, + struct curl_httppost **last_post) +{ + struct curl_httppost *post; + post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1); + if(post) { + post->name = name; + post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); + post->contents = value; + post->contentslength = (long)contentslength; + post->buffer = buffer; + post->bufferlength = (long)bufferlength; + post->contenttype = contenttype; + post->contentheader = contentHeader; + post->showfilename = showfilename; + post->flags = flags; + } + else + return NULL; + + if (parent_post) { + /* now, point our 'more' to the original 'more' */ + post->more = parent_post->more; + + /* then move the original 'more' to point to ourselves */ + parent_post->more = post; + } + else { + /* make the previous point to this */ + if(*last_post) + (*last_post)->next = post; + else + (*httppost) = post; + + (*last_post) = post; + } + return post; +} + +/*************************************************************************** + * + * AddFormInfo() + * + * Adds a FormInfo structure to the list presented by parent_form_info. + * + * Returns newly allocated FormInfo on success and NULL if malloc failed/ + * parent_form_info is NULL. + * + ***************************************************************************/ +static FormInfo * AddFormInfo(char *value, + char *contenttype, + FormInfo *parent_form_info) +{ + FormInfo *form_info; + form_info = (FormInfo *)malloc(sizeof(FormInfo)); + if(form_info) { + memset(form_info, 0, sizeof(FormInfo)); + if (value) + form_info->value = value; + if (contenttype) + form_info->contenttype = contenttype; + form_info->flags = HTTPPOST_FILENAME; + } + else + return NULL; + + if (parent_form_info) { + /* now, point our 'more' to the original 'more' */ + form_info->more = parent_form_info->more; + + /* then move the original 'more' to point to ourselves */ + parent_form_info->more = form_info; + } + else + return NULL; + + return form_info; +} + +/*************************************************************************** + * + * ContentTypeForFilename() + * + * Provides content type for filename if one of the known types (else + * (either the prevtype or the default is returned). + * + * Returns some valid contenttype for filename. + * + ***************************************************************************/ +static const char * ContentTypeForFilename (const char *filename, + const char *prevtype) +{ + const char *contenttype = NULL; + unsigned int i; + /* + * No type was specified, we scan through a few well-known + * extensions and pick the first we match! + */ + struct ContentType { + const char *extension; + const char *type; + }; + static const struct ContentType ctts[]={ + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".txt", "text/plain"}, + {".html", "text/html"} + }; + + if(prevtype) + /* default to the previously set/used! */ + contenttype = prevtype; + else + /* It seems RFC1867 defines no Content-Type to default to + text/plain so we don't actually need to set this: */ + contenttype = HTTPPOST_CONTENTTYPE_DEFAULT; + + for(i=0; i= strlen(ctts[i].extension)) { + if(strequal(filename + + strlen(filename) - strlen(ctts[i].extension), + ctts[i].extension)) { + contenttype = ctts[i].type; + break; + } + } + } + /* we have a contenttype by now */ + return contenttype; +} + +/*************************************************************************** + * + * memdup() + * + * Copies the 'source' data to a newly allocated buffer buffer (that is + * returned). Uses buffer_length if not null, else uses strlen to determine + * the length of the buffer to be copied + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +static char *memdup(const char *src, size_t buffer_length) +{ + size_t length; + bool add = FALSE; + char *buffer; + + if (buffer_length) + length = buffer_length; + else { + length = strlen(src); + add = TRUE; + } + buffer = (char*)malloc(length+add); + if (!buffer) + return NULL; /* fail */ + + memcpy(buffer, src, length); + + /* if length unknown do null termination */ + if (add) + buffer[length] = '\0'; + + return buffer; +} + +/*************************************************************************** + * + * FormAdd() + * + * Stores a formpost parameter and builds the appropriate linked list. + * + * Has two principal functionalities: using files and byte arrays as + * post parts. Byte arrays are either copied or just the pointer is stored + * (as the user requests) while for files only the filename and not the + * content is stored. + * + * While you may have only one byte array for each name, multiple filenames + * are allowed (and because of this feature CURLFORM_END is needed after + * using CURLFORM_FILE). + * + * Examples: + * + * Simple name/value pair with copied contents: + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); + * + * name/value pair where only the content pointer is remembered: + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); + * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) + * + * storing a filename (CONTENTTYPE is optional!): + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", + * CURLFORM_END); + * + * storing multiple filenames: + * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error) + * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ + +static +CURLFORMcode FormAdd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + va_list params) +{ + FormInfo *first_form, *current_form, *form = NULL; + CURLFORMcode return_value = CURL_FORMADD_OK; + const char *prevtype = NULL; + struct curl_httppost *post = NULL; + CURLformoption option; + 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're parsing an + array that we got passed to us. If FALSE we're parsing the input + va_list arguments. */ + bool array_state = FALSE; + + /* + * We need to allocate the first struct to fill in. + */ + first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1); + if(!first_form) + return CURL_FORMADD_MEMORY; + + current_form = first_form; + + /* + * Loop through all the options set. Break if we have an error to report. + */ + while (return_value == CURL_FORMADD_OK) { + + /* first see if we have more parts of the array param */ + if ( array_state ) { + /* get the upcoming option from the given array */ + option = forms->option; + array_value = (char *)forms->value; + + forms++; /* advance this to next entry */ + if (CURLFORM_END == option) { + /* end of array state */ + array_state = FALSE; + continue; + } + } + else { + /* This is not array-state, get next option */ + option = va_arg(params, CURLformoption); + if (CURLFORM_END == option) + break; + } + + switch (option) { + case CURLFORM_ARRAY: + if(array_state) + /* we don't support an array from within an array */ + return_value = CURL_FORMADD_ILLEGAL_ARRAY; + else { + forms = va_arg(params, struct curl_forms *); + if (forms) + array_state = TRUE; + else + return_value = CURL_FORMADD_NULL; + } + break; + + /* + * Set the Name property. + */ + case CURLFORM_PTRNAME: +#ifdef CURL_DOES_CONVERSIONS + /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll + have safe memory for the eventual conversion */ +#else + current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ +#endif + case CURLFORM_COPYNAME: + if (current_form->name) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *name = array_state? + array_value:va_arg(params, char *); + if (name) + current_form->name = name; /* store for the moment */ + else + return_value = CURL_FORMADD_NULL; + } + break; + case CURLFORM_NAMELENGTH: + if (current_form->namelength) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->namelength = + array_state?(long)array_value:(long)va_arg(params, long); + break; + + /* + * Set the contents property. + */ + case CURLFORM_PTRCONTENTS: + current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */ + case CURLFORM_COPYCONTENTS: + if (current_form->value) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *value = + array_state?array_value:va_arg(params, char *); + if (value) + current_form->value = value; /* store for the moment */ + else + return_value = CURL_FORMADD_NULL; + } + break; + case CURLFORM_CONTENTSLENGTH: + if (current_form->contentslength) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->contentslength = + array_state?(long)array_value:va_arg(params, long); + break; + + /* Get contents from a given file name */ + case CURLFORM_FILECONTENT: + if (current_form->flags != 0) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *filename = array_state? + array_value:va_arg(params, char *); + if (filename) { + current_form->value = strdup(filename); + if(!current_form->value) + return_value = CURL_FORMADD_MEMORY; + else { + current_form->flags |= HTTPPOST_READFILE; + current_form->value_alloc = TRUE; + } + } + else + return_value = CURL_FORMADD_NULL; + } + break; + + /* We upload a file */ + case CURLFORM_FILE: + { + char *filename = array_state?array_value: + va_arg(params, char *); + + if (current_form->value) { + if (current_form->flags & HTTPPOST_FILENAME) { + if (filename) { + if ((current_form = AddFormInfo(strdup(filename), + NULL, current_form)) == NULL) + return_value = CURL_FORMADD_MEMORY; + } + else + return_value = CURL_FORMADD_NULL; + } + else + return_value = CURL_FORMADD_OPTION_TWICE; + } + else { + if (filename) { + current_form->value = strdup(filename); + if(!current_form->value) + return_value = CURL_FORMADD_MEMORY; + else { + current_form->flags |= HTTPPOST_FILENAME; + current_form->value_alloc = TRUE; + } + } + else + return_value = CURL_FORMADD_NULL; + } + break; + } + + case CURLFORM_BUFFER: + { + char *filename = array_state?array_value: + va_arg(params, char *); + + if (current_form->value) { + if (current_form->flags & HTTPPOST_BUFFER) { + if (filename) { + if ((current_form = AddFormInfo(strdup(filename), + NULL, current_form)) == NULL) + return_value = CURL_FORMADD_MEMORY; + } + else + return_value = CURL_FORMADD_NULL; + } + else + return_value = CURL_FORMADD_OPTION_TWICE; + } + else { + if (filename) { + current_form->value = strdup(filename); + if(!current_form->value) + return_value = CURL_FORMADD_MEMORY; + } + else + return_value = CURL_FORMADD_NULL; + current_form->flags |= HTTPPOST_BUFFER; + } + break; + } + + case CURLFORM_BUFFERPTR: + current_form->flags |= HTTPPOST_PTRBUFFER; + if (current_form->buffer) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + char *buffer = + array_state?array_value:va_arg(params, char *); + if (buffer) + current_form->buffer = buffer; /* store for the moment */ + else + return_value = CURL_FORMADD_NULL; + } + break; + + case CURLFORM_BUFFERLENGTH: + if (current_form->bufferlength) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->bufferlength = + array_state?(long)array_value:va_arg(params, long); + break; + + case CURLFORM_CONTENTTYPE: + { + char *contenttype = + array_state?array_value:va_arg(params, char *); + if (current_form->contenttype) { + if (current_form->flags & HTTPPOST_FILENAME) { + if (contenttype) { + if ((current_form = AddFormInfo(NULL, + strdup(contenttype), + current_form)) == NULL) + return_value = CURL_FORMADD_MEMORY; + } + else + return_value = CURL_FORMADD_NULL; + } + else + return_value = CURL_FORMADD_OPTION_TWICE; + } + else { + if (contenttype) { + current_form->contenttype = strdup(contenttype); + if(!current_form->contenttype) + return_value = CURL_FORMADD_MEMORY; + else + current_form->contenttype_alloc = TRUE; + } + else + return_value = CURL_FORMADD_NULL; + } + break; + } + case CURLFORM_CONTENTHEADER: + { + /* this "cast increases required alignment of target type" but + we consider it OK anyway */ + struct curl_slist* list = array_state? + (struct curl_slist*)array_value: + va_arg(params, struct curl_slist*); + + if( current_form->contentheader ) + return_value = CURL_FORMADD_OPTION_TWICE; + else + current_form->contentheader = list; + + break; + } + case CURLFORM_FILENAME: + { + char *filename = array_state?array_value: + va_arg(params, char *); + if( current_form->showfilename ) + return_value = CURL_FORMADD_OPTION_TWICE; + else { + current_form->showfilename = strdup(filename); + if(!current_form->showfilename) + return_value = CURL_FORMADD_MEMORY; + else + current_form->showfilename_alloc = TRUE; + } + break; + } + default: + return_value = CURL_FORMADD_UNKNOWN_OPTION; + } + } + + if(CURL_FORMADD_OK == return_value) { + /* go through the list, check for copleteness and if everything is + * alright add the HttpPost item otherwise set return_value accordingly */ + + post = NULL; + for(form = first_form; + form != NULL; + form = form->more) { + if ( ((!form->name || !form->value) && !post) || + ( (form->contentslength) && + (form->flags & HTTPPOST_FILENAME) ) || + ( (form->flags & HTTPPOST_FILENAME) && + (form->flags & HTTPPOST_PTRCONTENTS) ) || + + ( (!form->buffer) && + (form->flags & HTTPPOST_BUFFER) && + (form->flags & HTTPPOST_PTRBUFFER) ) || + + ( (form->flags & HTTPPOST_READFILE) && + (form->flags & HTTPPOST_PTRCONTENTS) ) + ) { + return_value = CURL_FORMADD_INCOMPLETE; + break; + } + else { + if ( ((form->flags & HTTPPOST_FILENAME) || + (form->flags & HTTPPOST_BUFFER)) && + !form->contenttype ) { + /* our contenttype is missing */ + form->contenttype + = strdup(ContentTypeForFilename(form->value, prevtype)); + if(!form->contenttype) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->contenttype_alloc = TRUE; + } + if ( !(form->flags & HTTPPOST_PTRNAME) && + (form == first_form) ) { + /* copy name (without strdup; possibly contains null characters) */ + form->name = memdup(form->name, form->namelength); + if (!form->name) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->name_alloc = TRUE; + } + if ( !(form->flags & HTTPPOST_FILENAME) && + !(form->flags & HTTPPOST_READFILE) && + !(form->flags & HTTPPOST_PTRCONTENTS) && + !(form->flags & HTTPPOST_PTRBUFFER) ) { + /* copy value (without strdup; possibly contains null characters) */ + form->value = memdup(form->value, form->contentslength); + if (!form->value) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->value_alloc = TRUE; + } + post = AddHttpPost(form->name, form->namelength, + form->value, form->contentslength, + form->buffer, form->bufferlength, + form->contenttype, form->flags, + form->contentheader, form->showfilename, + post, httppost, + last_post); + + if(!post) { + return_value = CURL_FORMADD_MEMORY; + break; + } + + if (form->contenttype) + prevtype = form->contenttype; + } + } + } + + if(return_value) { + /* we return on error, free possibly allocated fields */ + if(!form) + form = current_form; + if(form) { + if(form->name_alloc) + free(form->name); + if(form->value_alloc) + free(form->value); + if(form->contenttype_alloc) + free(form->contenttype); + if(form->showfilename_alloc) + free(form->showfilename); + } + } + + /* always delete the allocated memory before returning */ + form = first_form; + while (form != NULL) { + FormInfo *delete_form; + + delete_form = form; + form = form->more; + free (delete_form); + } + + return return_value; +} + +/* + * curl_formadd() is a public API to add a section to the multipart formpost. + */ + +CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...) +{ + va_list arg; + CURLFORMcode result; + va_start(arg, last_post); + result = FormAdd(httppost, last_post, arg); + va_end(arg); + return result; +} + +/* + * AddFormData() adds a chunk of data to the FormData linked list. + * + * size is incremented by the chunk length, unless it is NULL + */ +static CURLcode AddFormData(struct FormData **formp, + enum formtype type, + const void *line, + size_t length, + curl_off_t *size) +{ + struct FormData *newform = (struct FormData *) + malloc(sizeof(struct FormData)); + if (!newform) + return CURLE_OUT_OF_MEMORY; + newform->next = NULL; + + /* we make it easier for plain strings: */ + if(!length) + length = strlen((char *)line); + + newform->line = (char *)malloc(length+1); + if (!newform->line) { + free(newform); + return CURLE_OUT_OF_MEMORY; + } + memcpy(newform->line, line, length); + newform->length = length; + newform->line[length]=0; /* zero terminate for easier debugging */ + newform->type = type; + + if(*formp) { + (*formp)->next = newform; + *formp = newform; + } + else + *formp = newform; + + if (size) { + if((type == FORM_DATA) || (type == FORM_CONTENT)) + *size += length; + else { + /* Since this is a file to be uploaded here, add the size of the actual + file */ + if(!strequal("-", newform->line)) { + struct_stat file; + if(!stat(newform->line, &file)) { + *size += file.st_size; + } + } + } + } + return CURLE_OK; +} + +/* + * AddFormDataf() adds printf()-style formatted data to the formdata chain. + */ + +static CURLcode AddFormDataf(struct FormData **formp, + curl_off_t *size, + const char *fmt, ...) +{ + char s[4096]; + va_list ap; + va_start(ap, fmt); + vsnprintf(s, sizeof(s), fmt, ap); + va_end(ap); + + return AddFormData(formp, FORM_DATA, s, 0, size); +} + +/* + * Curl_formclean() is used from http.c, this cleans a built FormData linked + * list + */ +void Curl_formclean(struct FormData **form_ptr) +{ + struct FormData *next, *form; + + form = *form_ptr; + if(!form) + return; + + do { + next=form->next; /* the following form line */ + free(form->line); /* free the line */ + free(form); /* free the struct */ + + } while ((form = next) != NULL); /* continue */ + + *form_ptr = NULL; +} + +#ifdef CURL_DOES_CONVERSIONS +/* + * Curl_formcovert() is used from http.c, this converts any + form items that need to be sent in the network encoding. + Returns CURLE_OK on success. + */ +CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form) +{ + struct FormData *next; + CURLcode rc; + + if(!form) + return CURLE_OK; + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + do { + next=form->next; /* the following form line */ + if (form->type == FORM_DATA) { + rc = Curl_convert_to_network(data, form->line, form->length); + /* Curl_convert_to_network calls failf if unsuccessful */ + if (rc != CURLE_OK) + return rc; + } + } while ((form = next) != NULL); /* continue */ + return CURLE_OK; +} +#endif /* CURL_DOES_CONVERSIONS */ + +/* + * curl_formget() + * Serialize a curl_httppost struct. + * Returns 0 on success. + */ +int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append) +{ + CURLcode rc; + curl_off_t size; + struct FormData *data, *ptr; + + rc = Curl_getFormData(&data, form, NULL, &size); + if (rc != CURLE_OK) + return (int)rc; + + for (ptr = data; ptr; ptr = ptr->next) { + if (ptr->type == FORM_FILE) { + char buffer[8192]; + size_t read; + struct Form temp; + + Curl_FormInit(&temp, ptr); + + do { + read = readfromfile(&temp, buffer, sizeof(buffer)); + if ((read == (size_t) -1) || (read != append(arg, buffer, read))) { + if (temp.fp) { + fclose(temp.fp); + } + Curl_formclean(&data); + return -1; + } + } while (read == sizeof(buffer)); + } else { + if (ptr->length != append(arg, ptr->line, ptr->length)) { + Curl_formclean(&data); + return -1; + } + } + } + Curl_formclean(&data); + return 0; +} + +/* + * curl_formfree() is an external function to free up a whole form post + * chain + */ +void curl_formfree(struct curl_httppost *form) +{ + struct curl_httppost *next; + + if(!form) + /* no form to free, just get out of this */ + return; + + do { + next=form->next; /* the following form line */ + + /* recurse to sub-contents */ + if(form->more) + curl_formfree(form->more); + + if( !(form->flags & HTTPPOST_PTRNAME) && form->name) + free(form->name); /* free the name */ + if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents) + free(form->contents); /* free the contents */ + if(form->contenttype) + free(form->contenttype); /* free the content type */ + if(form->showfilename) + free(form->showfilename); /* free the faked file name */ + free(form); /* free the struct */ + + } while ((form = next) != NULL); /* continue */ +} + +#ifndef HAVE_BASENAME +/* + (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 + Edition) + + The basename() function shall take the pathname pointed to by path and + return a pointer to the final component of the pathname, deleting any + trailing '/' characters. + + If the string pointed to by path consists entirely of the '/' character, + basename() shall return a pointer to the string "/". If the string pointed + to by path is exactly "//", it is implementation-defined whether '/' or "//" + is returned. + + If path is a null pointer or points to an empty string, basename() shall + return a pointer to the string ".". + + The basename() function may modify the string pointed to by path, and may + return a pointer to static storage that may then be overwritten by a + subsequent call to basename(). + + The basename() function need not be reentrant. A function that is not + required to be reentrant is not required to be thread-safe. + +*/ +static char *basename(char *path) +{ + /* Ignore all the details above for now and make a quick and simple + implementaion here */ + char *s1; + char *s2; + + s1=strrchr(path, '/'); + s2=strrchr(path, '\\'); + + if(s1 && s2) { + path = (s1 > s2? s1 : s2)+1; + } + else if(s1) + path = s1 + 1; + else if(s2) + path = s2 + 1; + + return path; +} +#endif + +static char *strippath(char *fullfile) +{ + char *filename; + char *base; + filename = strdup(fullfile); /* duplicate since basename() may ruin the + buffer it works on */ + if(!filename) + return NULL; + base = strdup(basename(filename)); + + free(filename); /* free temporary buffer */ + + return base; /* returns an allocated string! */ +} + +/* + * Curl_getFormData() converts a linked list of "meta data" into a complete + * (possibly huge) multipart formdata. The input list is in 'post', while the + * output resulting linked lists gets stored in '*finalform'. *sizep will get + * the total size of the whole POST. + * A multipart/form_data content-type is built, unless a custom content-type + * is passed in 'custom_content_type'. + */ + +CURLcode Curl_getFormData(struct FormData **finalform, + struct curl_httppost *post, + const char *custom_content_type, + curl_off_t *sizep) +{ + struct FormData *form = NULL; + struct FormData *firstform; + struct curl_httppost *file; + CURLcode result = CURLE_OK; + + curl_off_t size=0; /* support potentially ENORMOUS formposts */ + char *boundary; + char *fileboundary=NULL; + struct curl_slist* curList; + + *finalform=NULL; /* default form is empty */ + + if(!post) + return result; /* no input => no output! */ + + boundary = Curl_FormBoundary(); + if(!boundary) + return CURLE_OUT_OF_MEMORY; + + /* Make the first line of the output */ + result = AddFormDataf(&form, NULL, + "%s; boundary=%s\r\n", + custom_content_type?custom_content_type: + "Content-Type: multipart/form-data", + boundary); + + if (result) { + free(boundary); + return result; + } + /* we DO NOT include that line in the total size of the POST, since it'll be + part of the header! */ + + firstform = form; + + do { + + if(size) { + result = AddFormDataf(&form, &size, "\r\n"); + if (result) + break; + } + + /* boundary */ + result = AddFormDataf(&form, &size, "--%s\r\n", boundary); + if (result) + break; + + /* Maybe later this should be disabled when a custom_content_type is + passed, since Content-Disposition is not meaningful for all multipart + types. + */ + result = AddFormDataf(&form, &size, + "Content-Disposition: form-data; name=\""); + if (result) + break; + + result = AddFormData(&form, FORM_DATA, post->name, post->namelength, + &size); + if (result) + break; + + result = AddFormDataf(&form, &size, "\""); + if (result) + break; + + if(post->more) { + /* If used, this is a link to more file names, we must then do + the magic to include several files with the same field name */ + + fileboundary = Curl_FormBoundary(); + + result = AddFormDataf(&form, &size, + "\r\nContent-Type: multipart/mixed," + " boundary=%s\r\n", + fileboundary); + if (result) + break; + } + + file = post; + + do { + + /* If 'showfilename' is set, that is a faked name passed on to us + to use to in the formpost. If that is not set, the actually used + local file name should be added. */ + + if(post->more) { + /* if multiple-file */ + char *filebasename= + (!file->showfilename)?strippath(file->contents):NULL; + + result = AddFormDataf(&form, &size, + "\r\n--%s\r\nContent-Disposition: " + "attachment; filename=\"%s\"", + fileboundary, + (file->showfilename?file->showfilename: + filebasename)); + if (filebasename) + free(filebasename); + if (result) + break; + } + else if((post->flags & HTTPPOST_FILENAME) || + (post->flags & HTTPPOST_BUFFER)) { + + char *filebasename= + (!post->showfilename)?strippath(post->contents):NULL; + + result = AddFormDataf(&form, &size, + "; filename=\"%s\"", + (post->showfilename?post->showfilename: + filebasename)); + if (filebasename) + free(filebasename); + + if (result) + break; + } + + if(file->contenttype) { + /* we have a specified type */ + result = AddFormDataf(&form, &size, + "\r\nContent-Type: %s", + file->contenttype); + if (result) + break; + } + + curList = file->contentheader; + while( curList ) { + /* Process the additional headers specified for this form */ + result = AddFormDataf( &form, &size, "\r\n%s", curList->data ); + if (result) + break; + curList = curList->next; + } + if (result) { + Curl_formclean(&firstform); + free(boundary); + return result; + } + +#if 0 + /* The header Content-Transfer-Encoding: seems to confuse some receivers + * (like the built-in PHP engine). While I can't see any reason why it + * should, I can just as well skip this to the benefit of the users who + * are using such confused receivers. + */ + + if(file->contenttype && + !checkprefix("text/", file->contenttype)) { + /* this is not a text content, mention our binary encoding */ + result = AddFormDataf(&form, &size, + "\r\nContent-Transfer-Encoding: binary"); + if (result) + break; + } +#endif + + result = AddFormDataf(&form, &size, "\r\n\r\n"); + if (result) + break; + + if((post->flags & HTTPPOST_FILENAME) || + (post->flags & HTTPPOST_READFILE)) { + /* we should include the contents from the specified file */ + FILE *fileread; + + fileread = strequal("-", file->contents)? + stdin:fopen(file->contents, "rb"); /* binary read for win32 */ + + /* + * VMS: This only allows for stream files on VMS. Stream files are + * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC, + * every record needs to have a \n appended & 1 added to SIZE + */ + + if(fileread) { + if(fileread != stdin) { + /* close the file again */ + fclose(fileread); + /* add the file name only - for later reading from this */ + result = AddFormData(&form, FORM_FILE, file->contents, 0, &size); + } + else { + /* When uploading from stdin, we can't know the size of the file, + * thus must read the full file as before. We *could* use chunked + * transfer-encoding, but that only works for HTTP 1.1 and we + * can't be sure we work with such a server. + */ + size_t nread; + char buffer[512]; + while ((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { + result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); + if (result) + break; + } + } + + if (result) { + Curl_formclean(&firstform); + free(boundary); + return result; + } + + } + else { +#ifdef _FORM_DEBUG + fprintf(stderr, + "\n==> Curl_getFormData couldn't open/read \"%s\"\n", + file->contents); +#endif + Curl_formclean(&firstform); + free(boundary); + *finalform = NULL; + return CURLE_READ_ERROR; + } + + } + else if (post->flags & HTTPPOST_BUFFER) { + /* include contents of buffer */ + result = AddFormData(&form, FORM_CONTENT, post->buffer, + post->bufferlength, &size); + if (result) + break; + } + + else { + /* include the contents we got */ + result = AddFormData(&form, FORM_CONTENT, post->contents, + post->contentslength, &size); + if (result) + break; + } + } while ((file = file->more) != NULL); /* for each specified file for this field */ + if (result) { + Curl_formclean(&firstform); + free(boundary); + return result; + } + + if(post->more) { + /* this was a multiple-file inclusion, make a termination file + boundary: */ + result = AddFormDataf(&form, &size, + "\r\n--%s--", + fileboundary); + free(fileboundary); + if (result) + break; + } + + } while ((post = post->next) != NULL); /* for each field */ + if (result) { + Curl_formclean(&firstform); + free(boundary); + return result; + } + + /* end-boundary for everything */ + result = AddFormDataf(&form, &size, + "\r\n--%s--\r\n", + boundary); + if (result) { + Curl_formclean(&firstform); + free(boundary); + return result; + } + + *sizep = size; + + free(boundary); + + *finalform=firstform; + + return result; +} + +/* + * Curl_FormInit() inits the struct 'form' points to with the 'formdata' + * and resets the 'sent' counter. + */ +int Curl_FormInit(struct Form *form, struct FormData *formdata ) +{ + if(!formdata) + return 1; /* error */ + + form->data = formdata; + form->sent = 0; + form->fp = NULL; + + return 0; +} + +static size_t readfromfile(struct Form *form, char *buffer, size_t size) +{ + size_t nread; + if(!form->fp) { + /* this file hasn't yet been opened */ + form->fp = fopen(form->data->line, "rb"); /* b is for binary */ + if(!form->fp) + return (size_t)-1; /* failure */ + } + nread = fread(buffer, 1, size, form->fp); + + if(nread != size) { + /* this is the last chunk from the file, move on */ + fclose(form->fp); + form->fp = NULL; + form->data = form->data->next; + } + + return nread; +} + +/* + * Curl_FormReader() is the fread() emulation function that will be used to + * deliver the formdata to the transfer loop and then sent away to the peer. + */ +size_t Curl_FormReader(char *buffer, + size_t size, + size_t nitems, + FILE *mydata) +{ + struct Form *form; + size_t wantedsize; + size_t gotsize = 0; + + form=(struct Form *)mydata; + + wantedsize = size * nitems; + + if(!form->data) + return 0; /* nothing, error, empty */ + + if(form->data->type == FORM_FILE) { + gotsize = readfromfile(form, buffer, wantedsize); + + if(gotsize) + /* If positive or -1, return. If zero, continue! */ + return gotsize; + } + do { + + if( (form->data->length - form->sent ) > wantedsize - gotsize) { + + memcpy(buffer + gotsize , form->data->line + form->sent, + wantedsize - gotsize); + + form->sent += wantedsize-gotsize; + + return wantedsize; + } + + memcpy(buffer+gotsize, + form->data->line + form->sent, + (form->data->length - form->sent) ); + gotsize += form->data->length - form->sent; + + form->sent = 0; + + form->data = form->data->next; /* advance */ + + } while(form->data && (form->data->type != FORM_FILE)); + /* If we got an empty line and we have more data, we proceed to the next + line immediately to avoid returning zero before we've reached the end. + This is the bug reported November 22 1999 on curl 6.3. (Daniel) */ + + return gotsize; +} + +/* + * Curl_formpostheader() returns the first line of the formpost, the + * request-header part (which is not part of the request-body like the rest of + * the post). + */ +char *Curl_formpostheader(void *formp, size_t *len) +{ + char *header; + struct Form *form=(struct Form *)formp; + + if(!form->data) + return 0; /* nothing, ERROR! */ + + header = form->data->line; + *len = form->data->length; + + form->data = form->data->next; /* advance */ + + return header; +} + + +#ifdef _FORM_DEBUG +int FormAddTest(const char * errormsg, + struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...) +{ + int result; + va_list arg; + va_start(arg, last_post); + if ((result = FormAdd(httppost, last_post, arg))) + fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result, + errormsg); + va_end(arg); + return result; +} + + +int main() +{ + char name1[] = "simple_COPYCONTENTS"; + char name2[] = "COPYCONTENTS_+_CONTENTTYPE"; + char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"; + char name4[] = "simple_PTRCONTENTS"; + char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH"; + char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"; + char name7[] = "FILE1_+_CONTENTTYPE"; + char name8[] = "FILE1_+_FILE2"; + char name9[] = "FILE1_+_FILE2_+_FILE3"; + char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3"; + char name11[] = "FILECONTENT"; + char value1[] = "value for simple COPYCONTENTS"; + char value2[] = "value for COPYCONTENTS + CONTENTTYPE"; + char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH"; + char value4[] = "value for simple PTRCONTENTS"; + char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH"; + char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE"; + char value7[] = "inet_ntoa_r.h"; + char value8[] = "Makefile.b32"; + char type2[] = "image/gif"; + char type6[] = "text/plain"; + char type7[] = "text/html"; + int name3length = strlen(name3); + int value3length = strlen(value3); + int value5length = strlen(value4); + int value6length = strlen(value5); + int errors = 0; + CURLcode rc; + size_t size; + size_t nread; + char buffer[4096]; + struct curl_httppost *httppost=NULL; + struct curl_httppost *last_post=NULL; + struct curl_forms forms[4]; + + struct FormData *form; + struct Form formread; + + if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post, + CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1, + CURLFORM_END)) + ++errors; + if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post, + CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2, + CURLFORM_CONTENTTYPE, type2, CURLFORM_END)) + ++errors; + /* make null character at start to check that contentslength works + correctly */ + name3[1] = '\0'; + value3[1] = '\0'; + if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test", + &httppost, &last_post, + CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3, + CURLFORM_CONTENTSLENGTH, value3length, + CURLFORM_NAMELENGTH, name3length, CURLFORM_END)) + ++errors; + if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post, + CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4, + CURLFORM_END)) + ++errors; + /* make null character at start to check that contentslength works + correctly */ + value5[1] = '\0'; + if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post, + CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5, + CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END)) + ++errors; + /* make null character at start to check that contentslength works + correctly */ + value6[1] = '\0'; + if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test", + &httppost, &last_post, + CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6, + CURLFORM_CONTENTSLENGTH, value6length, + CURLFORM_CONTENTTYPE, type6, CURLFORM_END)) + ++errors; + if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post, + CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7, + CURLFORM_CONTENTTYPE, type7, CURLFORM_END)) + ++errors; + if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post, + CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7, + CURLFORM_FILE, value8, CURLFORM_END)) + ++errors; + if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post, + CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7, + CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END)) + ++errors; + forms[0].option = CURLFORM_FILE; + forms[0].value = value7; + forms[1].option = CURLFORM_FILE; + forms[1].value = value8; + forms[2].option = CURLFORM_FILE; + forms[2].value = value7; + forms[3].option = CURLFORM_END; + if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post, + CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms, + CURLFORM_END)) + ++errors; + if (FormAddTest("FILECONTENT test", &httppost, &last_post, + CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7, + CURLFORM_END)) + ++errors; + + rc = Curl_getFormData(&form, httppost, NULL, &size); + if(rc != CURLE_OK) { + if(rc != CURLE_READ_ERROR) { + const char *errortext = curl_easy_strerror(rc); + fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext); + } + return 0; + } + + Curl_FormInit(&formread, form); + + do { + nread = Curl_FormReader(buffer, 1, sizeof(buffer), + (FILE *)&formread); + + if(nread < 1) + break; + fwrite(buffer, nread, 1, stdout); + } while(1); + + fprintf(stdout, "size: %d\n", size); + if (errors) + fprintf(stdout, "\n==> %d Test(s) failed!\n", errors); + else + fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n"); + + return 0; +} + +#endif /* _FORM_DEBUG */ + +#else /* CURL_DISABLE_HTTP */ +CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...) +{ + (void)httppost; + (void)last_post; + return CURL_FORMADD_DISABLED; +} + +int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append) +{ + (void) form; + (void) arg; + (void) append; + return CURL_FORMADD_DISABLED; +} + +void curl_formfree(struct curl_httppost *form) +{ + (void)form; + /* does nothing HTTP is disabled */ +} + +#endif /* CURL_DISABLE_HTTP */ + +#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) + +/* + * Curl_FormBoundary() creates a suitable boundary string and returns an + * allocated one. This is also used by SSL-code so it must be present even + * if HTTP is disabled! + */ +char *Curl_FormBoundary(void) +{ + char *retstring; + static int randomizer; /* this is just so that two boundaries within + the same form won't be identical */ + size_t i; + + static const char table16[]="abcdef0123456789"; + + retstring = (char *)malloc(BOUNDARY_LENGTH+1); + + if(!retstring) + return NULL; /* failed */ + + srand((unsigned int)time(NULL)+randomizer++); /* seed */ + + strcpy(retstring, "----------------------------"); + + for(i=strlen(retstring); i, 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +enum formtype { + FORM_DATA, /* form metadata (convert to network encoding if necessary) */ + FORM_CONTENT, /* form content (never convert) */ + FORM_FILE /* 'line' points to a file name we should read from + to create the form data (never convert) */ +}; + +/* plain and simple linked list with lines to send */ +struct FormData { + struct FormData *next; + enum formtype type; + char *line; + size_t length; +}; + +struct Form { + struct FormData *data; /* current form line to send */ + size_t sent; /* number of bytes of the current line that has + already been sent in a previous invoke */ + FILE *fp; /* file to read from */ +}; + +/* used by FormAdd for temporary storage */ +typedef struct FormInfo { + char *name; + bool name_alloc; + size_t namelength; + char *value; + bool value_alloc; + size_t contentslength; + char *contenttype; + bool contenttype_alloc; + long flags; + char *buffer; /* pointer to existing buffer used for file upload */ + size_t bufferlength; + char *showfilename; /* The file name to show. If not set, the actual + file name will be used */ + bool showfilename_alloc; + struct curl_slist* contentheader; + struct FormInfo *more; +} FormInfo; + +int Curl_FormInit(struct Form *form, struct FormData *formdata ); + +CURLcode +Curl_getFormData(struct FormData **, + struct curl_httppost *post, + const char *custom_contenttype, + curl_off_t *size); + +/* fread() emulation */ +size_t Curl_FormReader(char *buffer, + size_t size, + size_t nitems, + FILE *mydata); + +/* + * Curl_formpostheader() returns the first line of the formpost, the + * request-header part (which is not part of the request-body like the rest of + * the post). + */ +char *Curl_formpostheader(void *formp, size_t *len); + +char *Curl_FormBoundary(void); + +void Curl_formclean(struct FormData **); + +CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *); + +#endif + diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c new file mode 100644 index 0000000..3ccbc43 --- /dev/null +++ b/Utilities/cmcurl/lib/ftp.c @@ -0,0 +1,3865 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_FTP +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef WIN32 + +#else /* probably some kind of unix */ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_UTSNAME_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef VMS +#include +#include +#endif +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "easyif.h" /* for Curl_convert_... prototypes */ + +#include "if2ip.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "ftp.h" + +#ifdef HAVE_KRB4 +#include "krb4.h" +#endif + +#include "strtoofft.h" +#include "strequal.h" +#include "sslgen.h" +#include "connect.h" +#include "strerror.h" +#include "memory.h" +#include "inet_ntop.h" +#include "select.h" +#include "parsedate.h" /* for the week day and month names */ +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "multiif.h" + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#ifdef CURLDEBUG +#include "memdebug.h" +#endif + +#ifdef HAVE_NI_WITHSCOPEID +#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID +#else +#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV +#endif + +/* Local API functions */ +static CURLcode ftp_sendquote(struct connectdata *conn, + struct curl_slist *quote); +static CURLcode ftp_quit(struct connectdata *conn); +static CURLcode ftp_parse_url_path(struct connectdata *conn); +static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done); +static void ftp_pasv_verbose(struct connectdata *conn, + Curl_addrinfo *ai, + char *newhost, /* ascii version */ + int port); +static CURLcode ftp_state_post_rest(struct connectdata *conn); +static CURLcode ftp_state_post_cwd(struct connectdata *conn); +static CURLcode ftp_state_quote(struct connectdata *conn, + bool init, ftpstate instate); +static CURLcode ftp_nb_type(struct connectdata *conn, + bool ascii, ftpstate state); +static int ftp_need_type(struct connectdata *conn, + bool ascii); + +/* easy-to-use macro: */ +#define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \ + return result +#define NBFTPSENDF(x,y,z) if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \ + return result + +static void freedirs(struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + + int i; + if(ftpc->dirs) { + for (i=0; i < ftpc->dirdepth; i++){ + if(ftpc->dirs[i]) { + free(ftpc->dirs[i]); + ftpc->dirs[i]=NULL; + } + } + free(ftpc->dirs); + ftpc->dirs = NULL; + } + if(ftp->file) { + free(ftp->file); + ftp->file = NULL; + } +} + +/* Returns non-zero if the given string contains CR (\r) or LF (\n), + which are not allowed within RFC 959 . + Note: The input string is in the client's encoding which might + not be ASCII, so escape sequences \r & \n must be used instead + of hex values 0x0d & 0x0a. +*/ +static bool isBadFtpString(const char *string) +{ + return (bool)((NULL != strchr(string, '\r')) || (NULL != strchr(string, '\n'))); +} + +/*********************************************************************** + * + * AllowServerConnect() + * + * When we've issue the PORT command, we have told the server to connect + * to us. This function will sit and wait here until the server has + * connected. + * + */ +static CURLcode AllowServerConnect(struct connectdata *conn) +{ + int timeout_ms; + struct SessionHandle *data = conn->data; + curl_socket_t sock = conn->sock[SECONDARYSOCKET]; + struct timeval now = Curl_tvnow(); + long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000; + long timeout = data->set.connecttimeout?data->set.connecttimeout: + (data->set.timeout?data->set.timeout: 0); + + if(timeout) { + timeout -= timespent; + if(timeout<=0) { + failf(data, "Timed out before server could connect to us"); + return CURLE_OPERATION_TIMEDOUT; + } + } + + /* We allow the server 60 seconds to connect to us, or a custom timeout. + Note the typecast here. */ + timeout_ms = (timeout?(int)timeout:60) * 1000; + + switch (Curl_select(sock, CURL_SOCKET_BAD, timeout_ms)) { + case -1: /* error */ + /* let's die here */ + failf(data, "Error while waiting for server connect"); + return CURLE_FTP_PORT_FAILED; + case 0: /* timeout */ + /* let's die here */ + failf(data, "Timeout while waiting for server connect"); + return CURLE_FTP_PORT_FAILED; + default: + /* we have received data here */ + { + curl_socket_t s = CURL_SOCKET_BAD; +#ifdef ENABLE_IPV6 + struct Curl_sockaddr_storage add; +#else + struct sockaddr_in add; +#endif + socklen_t size = (socklen_t) sizeof(add); + + if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { + size = sizeof(add); + + s=accept(sock, (struct sockaddr *) &add, &size); + } + sclose(sock); /* close the first socket */ + + if (CURL_SOCKET_BAD == s) { + /* DIE! */ + failf(data, "Error accept()ing server connect"); + return CURLE_FTP_PORT_FAILED; + } + infof(data, "Connection accepted from server\n"); + + conn->sock[SECONDARYSOCKET] = s; + Curl_nonblock(s, TRUE); /* enable non-blocking */ + } + break; + } + + return CURLE_OK; +} + +/* initialize stuff to prepare for reading a fresh new response */ +static void ftp_respinit(struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + ftpc->nread_resp = 0; + ftpc->linestart_resp = conn->data->state.buffer; +} + +/* macro to check for the last line in an FTP server response */ +#define lastline(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ + ISDIGIT(line[2]) && (' ' == line[3])) + +static CURLcode ftp_readresp(curl_socket_t sockfd, + struct connectdata *conn, + int *ftpcode, /* return the ftp-code if done */ + size_t *size) /* size of the response */ +{ + int perline; /* count bytes per line */ + bool keepon=TRUE; + ssize_t gotbytes; + char *ptr; + struct SessionHandle *data = conn->data; + char *buf = data->state.buffer; + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + int code = 0; + + if (ftpcode) + *ftpcode = 0; /* 0 for errors or not done */ + + ptr=buf + ftpc->nread_resp; + + perline= (int)(ptr-ftpc->linestart_resp); /* number of bytes in the current + line, so far */ + keepon=TRUE; + + while((ftpc->nread_respcache) { + /* we had data in the "cache", copy that instead of doing an actual + * read + * + * ftp->cache_size is cast to int 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. + */ + memcpy(ptr, ftpc->cache, (int)ftpc->cache_size); + gotbytes = (int)ftpc->cache_size; + free(ftpc->cache); /* free the cache */ + ftpc->cache = NULL; /* clear the pointer */ + ftpc->cache_size = 0; /* zero the size just in case */ + } + else { + int res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp, + &gotbytes); + if(res < 0) + /* EWOULDBLOCK */ + return CURLE_OK; /* return */ + +#ifdef CURL_DOES_CONVERSIONS + if((res == CURLE_OK) && (gotbytes > 0)) { + /* convert from the network encoding */ + result = res = Curl_convert_from_network(data, ptr, gotbytes); + /* Curl_convert_from_network calls failf if unsuccessful */ + } +#endif /* CURL_DOES_CONVERSIONS */ + + if(CURLE_OK != res) + keepon = FALSE; + } + + if(!keepon) + ; + else if(gotbytes <= 0) { + keepon = FALSE; + result = CURLE_RECV_ERROR; + failf(data, "FTP response reading failed"); + } + 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 */ + int i; + + conn->headerbytecount += gotbytes; + + ftpc->nread_resp += gotbytes; + for(i = 0; i < gotbytes; ptr++, i++) { + perline++; + if(*ptr=='\n') { + /* a newline is CRLF in ftp-talk, so the CR is ignored as + the line isn't really terminated until the LF comes */ + + /* output debug output if that is requested */ + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, + ftpc->linestart_resp, (size_t)perline, conn); + + /* + * 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(conn, CLIENTWRITE_HEADER, + ftpc->linestart_resp, perline); + if(result) + return result; + + if(perline>3 && lastline(ftpc->linestart_resp)) { + /* This is the end of the last line, copy the last line to the + start of the buffer and zero terminate, for old times sake (and + krb4)! */ + char *meow; + int n; + for(meow=ftpc->linestart_resp, n=0; meowlinestart_resp = ptr+1; /* advance pointer */ + i++; /* skip this before getting out */ + + *size = ftpc->nread_resp; /* size of the response */ + ftpc->nread_resp = 0; /* restart */ + break; + } + perline=0; /* line starts over here */ + ftpc->linestart_resp = ptr+1; + } + } + 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! */ + ftpc->cache_size = gotbytes - i; + ftpc->cache = (char *)malloc((int)ftpc->cache_size); + if(ftpc->cache) + memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size); + else + return CURLE_OUT_OF_MEMORY; /**BANG**/ + } + } /* there was data */ + + } /* while there's buffer left and loop is requested */ + + if(!result) + code = atoi(buf); + +#ifdef HAVE_KRB4 + /* handle the security-oriented responses 6xx ***/ + /* FIXME: some errorchecking perhaps... ***/ + switch(code) { + case 631: + Curl_sec_read_msg(conn, buf, prot_safe); + break; + case 632: + Curl_sec_read_msg(conn, buf, prot_private); + break; + case 633: + Curl_sec_read_msg(conn, buf, prot_confidential); + break; + default: + /* normal ftp stuff we pass through! */ + break; + } +#endif + + *ftpcode=code; /* return the initial number like this */ + + + /* store the latest code for later retrieval */ + conn->data->info.httpcode=code; + + return result; +} + +/* --- parse FTP server responses --- */ + +/* + * Curl_GetFTPResponse() is supposed to be invoked after each command sent to + * a remote FTP server. This function will wait and read all lines of the + * response and extract the relevant return code for the invoking function. + */ + +CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ + struct connectdata *conn, + int *ftpcode) /* return the ftp-code */ +{ + /* + * We cannot read just one byte per read() and then go back to select() as + * 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. */ + + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + int perline; /* count bytes per line */ + bool keepon=TRUE; + ssize_t gotbytes; + char *ptr; + long timeout; /* timeout in seconds */ + int interval_ms; + struct SessionHandle *data = conn->data; + char *line_start; + int code=0; /* default ftp "error code" to return */ + char *buf = data->state.buffer; + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct timeval now = Curl_tvnow(); + + if (ftpcode) + *ftpcode = 0; /* 0 for errors */ + + ptr=buf; + line_start = buf; + + *nreadp=0; + perline=0; + keepon=TRUE; + + while((*nreadpset.ftp_response_timeout ) + /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine + remaining time. Also, use "now" as opposed to "conn->now" + because ftp_response_timeout is only supposed to govern + the response for any given ftp response, not for the time + from connect to the given ftp response. */ + timeout = data->set.ftp_response_timeout - /* timeout time */ + Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */ + else if(data->set.timeout) + /* if timeout is requested, find out how much remaining time we have */ + timeout = data->set.timeout - /* timeout time */ + Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ + else + /* Even without a requested timeout, we only wait response_time + seconds for the full response to arrive before we bail out */ + timeout = ftpc->response_time - + Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */ + + if(timeout <=0 ) { + failf(data, "FTP response timeout"); + return CURLE_OPERATION_TIMEDOUT; /* already too little time */ + } + + if(!ftpc->cache) { + interval_ms = 1 * 1000; /* use 1 second timeout intervals */ + + switch (Curl_select(sockfd, CURL_SOCKET_BAD, interval_ms)) { + case -1: /* select() error, stop reading */ + result = CURLE_RECV_ERROR; + failf(data, "FTP response aborted due to select() error: %d", + Curl_sockerrno()); + break; + case 0: /* timeout */ + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + continue; /* just continue in our loop for the timeout duration */ + + default: + break; + } + } + if(CURLE_OK == result) { + /* + * This code previously didn't use the kerberos sec_read() code + * to read, but when we use Curl_read() it may do so. Do confirm + * that this is still ok and then remove this comment! + */ + if(ftpc->cache) { + /* we had data in the "cache", copy that instead of doing an actual + * read + * + * Dave Meyer, December 2003: + * ftp->cache_size is cast to int 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. + */ + memcpy(ptr, ftpc->cache, (int)ftpc->cache_size); + gotbytes = (int)ftpc->cache_size; + free(ftpc->cache); /* free the cache */ + ftpc->cache = NULL; /* clear the pointer */ + ftpc->cache_size = 0; /* zero the size just in case */ + } + else { + int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes); + if(res < 0) + /* EWOULDBLOCK */ + continue; /* go looping again */ + +#ifdef CURL_DOES_CONVERSIONS + if((res == CURLE_OK) && (gotbytes > 0)) { + /* convert from the network encoding */ + result = res = Curl_convert_from_network(data, ptr, gotbytes); + /* Curl_convert_from_network calls failf if unsuccessful */ + } +#endif /* CURL_DOES_CONVERSIONS */ + + if(CURLE_OK != res) + keepon = FALSE; + } + + if(!keepon) + ; + else if(gotbytes <= 0) { + keepon = FALSE; + result = CURLE_RECV_ERROR; + failf(data, "FTP response reading failed"); + } + 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 */ + int i; + + conn->headerbytecount += gotbytes; + + *nreadp += gotbytes; + for(i = 0; i < gotbytes; ptr++, i++) { + perline++; + if(*ptr=='\n') { + /* a newline is CRLF in ftp-talk, so the CR is ignored as + the line isn't really terminated until the LF comes */ + + /* output debug output if that is requested */ + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, + line_start, (size_t)perline, conn); + + /* + * 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(conn, CLIENTWRITE_HEADER, + line_start, perline); + if(result) + return result; + + if(perline>3 && lastline(line_start)) { + /* This is the end of the last line, copy the last + * line to the start of the buffer and zero terminate, + * for old times sake (and krb4)! */ + char *meow; + int n; + for(meow=line_start, n=0; meowcache_size = gotbytes - i; + ftpc->cache = (char *)malloc((int)ftpc->cache_size); + if(ftpc->cache) + memcpy(ftpc->cache, line_start, (int)ftpc->cache_size); + else + return CURLE_OUT_OF_MEMORY; /**BANG**/ + } + } /* there was data */ + } /* if(no error) */ + } /* while there's buffer left and loop is requested */ + + if(!result) + code = atoi(buf); + +#ifdef HAVE_KRB4 + /* handle the security-oriented responses 6xx ***/ + /* FIXME: some errorchecking perhaps... ***/ + switch(code) { + case 631: + Curl_sec_read_msg(conn, buf, prot_safe); + break; + case 632: + Curl_sec_read_msg(conn, buf, prot_private); + break; + case 633: + Curl_sec_read_msg(conn, buf, prot_confidential); + break; + default: + /* normal ftp stuff we pass through! */ + break; + } +#endif + + if(ftpcode) + *ftpcode=code; /* return the initial number like this */ + + /* store the latest code for later retrieval */ + conn->data->info.httpcode=code; + + return result; +} + +/* This is the ONLY way to change FTP state! */ +static void state(struct connectdata *conn, + ftpstate state) +{ +#ifdef CURLDEBUG + /* for debug purposes */ + const char *names[]={ + "STOP", + "WAIT220", + "AUTH", + "USER", + "PASS", + "ACCT", + "PBSZ", + "PROT", + "CCC", + "PWD", + "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", + "PASV", + "LIST", + "RETR", + "STOR", + "QUIT" + }; +#endif + struct ftp_conn *ftpc = &conn->proto.ftpc; +#ifdef CURLDEBUG + if(ftpc->state != state) + infof(conn->data, "FTP %p state change from %s to %s\n", + ftpc, names[ftpc->state], names[state]); +#endif + ftpc->state = state; +} + +static CURLcode ftp_state_user(struct connectdata *conn) +{ + CURLcode result; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + /* send USER */ + NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); + + state(conn, FTP_USER); + conn->data->state.ftp_trying_alternative = FALSE; + + return CURLE_OK; +} + +static CURLcode ftp_state_pwd(struct connectdata *conn) +{ + CURLcode result; + + /* send PWD to discover our entry point */ + NBFTPSENDF(conn, "PWD", NULL); + state(conn, FTP_PWD); + + return CURLE_OK; +} + +/* For the FTP "protocol connect" and "doing" phases only */ +int Curl_ftp_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(!numsocks) + return GETSOCK_BLANK; + + socks[0] = conn->sock[FIRSTSOCKET]; + + if(ftpc->sendleft) { + /* write mode */ + return GETSOCK_WRITESOCK(0); + } + + /* read mode */ + return GETSOCK_READSOCK(0); +} + +/* This is called after the FTP_QUOTE state is passed. + + ftp_state_cwd() sends the range of PWD commands to the server to change to + the correct directory. It may also need to send MKD commands to create + missing ones, if that option is enabled. +*/ +static CURLcode ftp_state_cwd(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(ftpc->cwddone) + /* already done and fine */ + result = ftp_state_post_cwd(conn); + else { + ftpc->count2 = 0; + if (conn->bits.reuse && ftpc->entrypath) { + /* This is a re-used connection. Since we change directory to where the + transfer is taking place, we must first get back to the original dir + where we ended up after login: */ + ftpc->count1 = 0; /* we count this as the first path, then we add one + for all upcoming ones in the ftp->dirs[] array */ + NBFTPSENDF(conn, "CWD %s", ftpc->entrypath); + state(conn, FTP_CWD); + } + else { + if(ftpc->dirdepth) { + ftpc->count1 = 1; + /* issue the first CWD, the rest is sent when the CWD responses are + received... */ + NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]); + state(conn, FTP_CWD); + } + else { + /* No CWD necessary */ + result = ftp_state_post_cwd(conn); + } + } + } + return result; +} + +typedef enum { + EPRT, + PORT, + DONE +} ftpport; + +static CURLcode ftp_state_use_port(struct connectdata *conn, + ftpport fcmd) /* start with this */ + +{ + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct SessionHandle *data=conn->data; + curl_socket_t portsock= CURL_SOCKET_BAD; + char myhost[256] = ""; + +#ifdef ENABLE_IPV6 + /****************************************************************** + * IPv6-specific section + */ + struct Curl_sockaddr_storage ss; + struct addrinfo *res, *ai; + socklen_t sslen; + char hbuf[NI_MAXHOST]; + struct sockaddr *sa=(struct sockaddr *)&ss; + char tmp[1024]; + const char *mode[] = { "EPRT", "PORT", NULL }; + int rc; + int error; + char *host=NULL; + struct Curl_dns_entry *h=NULL; + unsigned short port = 0; + + /* Step 1, figure out what address that is requested */ + + if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) { + /* attempt to get the address of the given interface name */ + if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf))) + /* not an interface, use the given string as host name instead */ + host = data->set.ftpport; + else + host = hbuf; /* use the hbuf for host name */ + } /* data->set.ftpport */ + + if(!host) { + /* 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], (struct sockaddr *)&ss, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, Curl_sockerrno()) ); + return CURLE_FTP_PORT_FAILED; + } + + if (sslen > (socklen_t)sizeof(ss)) + sslen = sizeof(ss); + rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, + 0, NIFLAGS); + if(rc) { + failf(data, "getnameinfo() returned %d \n", rc); + return CURLE_FTP_PORT_FAILED; + } + host = hbuf; /* use this host name */ + } + + rc = Curl_resolv(conn, host, 0, &h); + if(rc == CURLRESOLV_PENDING) + rc = Curl_wait_for_resolv(conn, &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! */ + + + /* step 2, create a socket for the requested address */ + + portsock = CURL_SOCKET_BAD; + error = 0; + for (ai = res; ai; ai = ai->ai_next) { + /* + * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype): + */ + if (ai->ai_socktype == 0) + ai->ai_socktype = conn->socktype; + + portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (portsock == CURL_SOCKET_BAD) { + error = Curl_sockerrno(); + continue; + } + break; + } + if(!ai) { + failf(data, "socket failure: %s", Curl_strerror(conn, error)); + return CURLE_FTP_PORT_FAILED; + } + + /* step 3, bind to a suitable local address */ + + /* Try binding the given address. */ + if (bind(portsock, ai->ai_addr, ai->ai_addrlen)) { + + /* It failed. Bind the address used for the control connection instead */ + sslen = sizeof(ss); + if (getsockname(conn->sock[FIRSTSOCKET], + (struct sockaddr *)sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, Curl_sockerrno()) ); + sclose(portsock); + return CURLE_FTP_PORT_FAILED; + } + + /* set port number to zero to make bind() pick "any" */ + if(((struct sockaddr *)sa)->sa_family == AF_INET) + ((struct sockaddr_in *)sa)->sin_port=0; + else + ((struct sockaddr_in6 *)sa)->sin6_port =0; + + if (sslen > (socklen_t)sizeof(ss)) + sslen = sizeof(ss); + + if(bind(portsock, (struct sockaddr *)sa, sslen)) { + failf(data, "bind failed: %s", Curl_strerror(conn, Curl_sockerrno())); + sclose(portsock); + return CURLE_FTP_PORT_FAILED; + } + } + + /* get the name again after the bind() so that we can extract the + port number it uses now */ + sslen = sizeof(ss); + if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, Curl_sockerrno()) ); + sclose(portsock); + return CURLE_FTP_PORT_FAILED; + } + + /* step 4, listen on the socket */ + + if (listen(portsock, 1)) { + failf(data, "socket failure: %s", Curl_strerror(conn, Curl_sockerrno())); + sclose(portsock); + return CURLE_FTP_PORT_FAILED; + } + + /* step 5, send the proper FTP command */ + + /* get a plain printable version of the numerical address to work with + below */ + Curl_printable_address(ai, myhost, sizeof(myhost)); + +#ifdef PF_INET6 + 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 + + for (; fcmd != DONE; fcmd++) { + + if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) + /* if disabled, goto next */ + continue; + + switch (sa->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + break; + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + break; + default: + break; + } + + if (EPRT == fcmd) { + /* + * Two fine examples from RFC2428; + * + * EPRT |1|132.235.1.2|6275| + * + * EPRT |2|1080::8:800:200C:417A|5282| + */ + + result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd], + ai->ai_family == AF_INET?1:2, + myhost, port); + if(result) + return result; + break; + } + else if (PORT == fcmd) { + char *source = myhost; + char *dest = tmp; + + if ((PORT == fcmd) && ai->ai_family != AF_INET) + continue; + + /* translate x.x.x.x to x,x,x,x */ + while(source && *source) { + if(*source == '.') + *dest=','; + else + *dest = *source; + dest++; + source++; + } + *dest = 0; + snprintf(dest, 20, ",%d,%d", port>>8, port&0xff); + + result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp); + if(result) + return result; + break; + } + } + + /* store which command was sent */ + ftpc->count1 = fcmd; + + /* we set the secondary socket variable to this for now, it is only so that + the cleanup function will close it in case we fail before the true + secondary stuff is made */ + if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = portsock; + +#else + /****************************************************************** + * IPv4-specific section + */ + struct sockaddr_in sa; + unsigned short porttouse; + bool sa_filled_in = FALSE; + Curl_addrinfo *addr = NULL; + unsigned short ip[4]; + bool freeaddr = TRUE; + socklen_t sslen = sizeof(sa); + + (void)fcmd; /* not used in the IPv4 code */ + if(data->set.ftpport) { + in_addr_t in; + + /* First check if the given name is an IP address */ + in=inet_addr(data->set.ftpport); + + if(in != CURL_INADDR_NONE) + /* this is an IPv4 address */ + addr = Curl_ip2addr(in, data->set.ftpport, 0); + else { + if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) { + /* The interface to IP conversion provided a dotted address */ + in=inet_addr(myhost); + addr = Curl_ip2addr(in, myhost, 0); + } + else if(strlen(data->set.ftpport)> 1) { + /* might be a host name! */ + struct Curl_dns_entry *h=NULL; + int rc = Curl_resolv(conn, data->set.ftpport, 0, &h); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING */ + rc = Curl_wait_for_resolv(conn, &h); + if(h) { + addr = h->addr; + /* when we return from this function, we can forget about this entry + so we can unlock it now already */ + Curl_resolv_unlock(data, h); + + freeaddr = FALSE; /* make sure we don't free 'addr' in this function + since it points to a DNS cache entry! */ + } /* (h) */ + else { + infof(data, "Failed to resolve host name %s\n", data->set.ftpport); + } + } /* strlen */ + } /* CURL_INADDR_NONE */ + } /* data->set.ftpport */ + + if(!addr) { + /* pick a suitable default here */ + + if (getsockname(conn->sock[FIRSTSOCKET], + (struct sockaddr *)&sa, &sslen)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, Curl_sockerrno()) ); + return CURLE_FTP_PORT_FAILED; + } + if (sslen > (socklen_t)sizeof(sa)) + sslen = sizeof(sa); + + sa_filled_in = TRUE; /* the sa struct is filled in */ + } + + if (addr || sa_filled_in) { + portsock = socket(AF_INET, SOCK_STREAM, 0); + if(CURL_SOCKET_BAD != portsock) { + + /* we set the secondary socket variable to this for now, it + is only so that the cleanup function will close it in case + we fail before the true secondary stuff is made */ + if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = portsock; + + if(!sa_filled_in) { + memcpy(&sa, addr->ai_addr, sslen); + sa.sin_addr.s_addr = INADDR_ANY; + } + + sa.sin_port = 0; + sslen = sizeof(sa); + + if(bind(portsock, (struct sockaddr *)&sa, sslen) == 0) { + /* we succeeded to bind */ + struct sockaddr_in add; + socklen_t socksize = sizeof(add); + + if(getsockname(portsock, (struct sockaddr *) &add, + &socksize)) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, Curl_sockerrno()) ); + return CURLE_FTP_PORT_FAILED; + } + porttouse = ntohs(add.sin_port); + + if ( listen(portsock, 1) < 0 ) { + failf(data, "listen(2) failed on socket"); + return CURLE_FTP_PORT_FAILED; + } + } + else { + failf(data, "bind(2) failed on socket"); + return CURLE_FTP_PORT_FAILED; + } + } + else { + failf(data, "socket(2) failed (%s)"); + return CURLE_FTP_PORT_FAILED; + } + } + else { + failf(data, "couldn't find IP address to use"); + return CURLE_FTP_PORT_FAILED; + } + + if(sa_filled_in) + Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr, + myhost, sizeof(myhost)); + else + Curl_printable_address(addr, myhost, sizeof(myhost)); + + if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3])) { + + infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n", + ip[0], ip[1], ip[2], ip[3], porttouse); + + result=Curl_nbftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d", + ip[0], ip[1], ip[2], ip[3], + porttouse >> 8, porttouse & 255); + if(result) + return result; + } + else + return CURLE_FTP_PORT_FAILED; + + if(freeaddr) + Curl_freeaddrinfo(addr); + + ftpc->count1 = PORT; + +#endif /* end of ipv4-specific code */ + + /* this tcpconnect assignment below is a hackish work-around to make the + multi interface with active FTP work - as it will not wait for a + (passive) connect in Curl_is_connected(). + + The *proper* fix is to make sure that the active connection from the + server is done in a non-blocking way. Currently, it is still BLOCKING. + */ + conn->bits.tcpconnect = TRUE; + + state(conn, FTP_PORT); + return result; +} + +static CURLcode ftp_state_use_pasv(struct connectdata *conn) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + /* + Here's the excecutive summary on what to do: + + PASV is RFC959, expect: + 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) + + LPSV is RFC1639, expect: + 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) + + EPSV is RFC2428, expect: + 229 Entering Extended Passive Mode (|||port|) + + */ + + const char *mode[] = { "EPSV", "PASV", NULL }; + int modeoff; + +#ifdef PF_INET6 + if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) + /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the + request and enable EPSV again! */ + conn->bits.ftp_use_epsv = TRUE; +#endif + + modeoff = conn->bits.ftp_use_epsv?0:1; + + result = Curl_nbftpsendf(conn, "%s", mode[modeoff]); + if(result) + return result; + + ftpc->count1 = modeoff; + state(conn, FTP_PASV); + infof(conn->data, "Connect data stream passively\n"); + + return result; +} + +/* REST is the last command in the chain of commands when a "head"-like + request is made. Thus, if an actual transfer is to be made this is where + we take off for real. */ +static CURLcode ftp_state_post_rest(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + struct SessionHandle *data = conn->data; + + if(ftp->no_transfer || conn->bits.no_body) { + /* doesn't transfer any data */ + ftp->no_transfer = TRUE; + + /* still possibly do PRE QUOTE jobs */ + state(conn, FTP_RETR_PREQUOTE); + result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); + } + else if(data->set.ftp_use_port) { + /* We have chosen to use the PORT (or similar) command */ + result = ftp_state_use_port(conn, EPRT); + } + else { + /* We have chosen (this is default) to use the PASV (or similar) command */ + result = ftp_state_use_pasv(conn); + } + return result; +} + +static CURLcode ftp_state_post_size(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + + if(ftp->no_transfer) { + /* if a "head"-like request is being made */ + + /* Determine if server can respond to REST command and therefore + whether it supports range */ + NBFTPSENDF(conn, "REST %d", 0); + + state(conn, FTP_REST); + } + else + result = ftp_state_post_rest(conn); + + return result; +} + +static CURLcode ftp_state_post_type(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + + if(ftp->no_transfer) { + /* if a "head"-like request is being made */ + + /* we know ftp->file is a valid pointer to a file name */ + NBFTPSENDF(conn, "SIZE %s", ftp->file); + + state(conn, FTP_SIZE); + } + else + result = ftp_state_post_size(conn); + + return result; +} + +static CURLcode ftp_state_post_listtype(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + /* If this output is to be machine-parsed, the NLST command might be better + to use, since the LIST command output is not specified or standard in any + way. It has turned out that the NLST list output is not the same on all + servers either... */ + + NBFTPSENDF(conn, "%s", + data->set.customrequest?data->set.customrequest: + (data->set.ftp_list_only?"NLST":"LIST")); + + state(conn, FTP_LIST); + + return result; +} + +static CURLcode ftp_state_post_retrtype(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* We've sent the TYPE, now we must send the list of prequote strings */ + + result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); + + return result; +} + +static CURLcode ftp_state_post_stortype(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* We've sent the TYPE, now we must send the list of prequote strings */ + + result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE); + + return result; +} + +static CURLcode ftp_state_post_mdtm(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + struct SessionHandle *data = conn->data; + + /* If we have selected NOBODY and HEADER, it means that we only want file + information. Which in FTP can't be much more than the file size and + date. */ + if(conn->bits.no_body && data->set.include_header && ftp->file && + ftp_need_type(conn, data->set.prefer_ascii)) { + /* The SIZE command is _not_ RFC 959 specified, and therefor many servers + may not support it! It is however the only way we have to get a file's + size! */ + + ftp->no_transfer = TRUE; /* this means no actual transfer will be made */ + + /* Some servers return different sizes for different modes, and thus we + must set the proper type before we check the size */ + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE); + if (result) + return result; + } + else + result = ftp_state_post_type(conn); + + return result; +} + +/* This is called after the CWD commands have been done in the beginning of + the DO phase */ +static CURLcode ftp_state_post_cwd(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + struct SessionHandle *data = conn->data; + + /* Requested time of file or time-depended transfer? */ + if((data->set.get_filetime || data->set.timecondition) && ftp->file) { + + /* we have requested to get the modified-time of the file, this is a white + spot as the MDTM is not mentioned in RFC959 */ + NBFTPSENDF(conn, "MDTM %s", ftp->file); + + state(conn, FTP_MDTM); + } + else + result = ftp_state_post_mdtm(conn); + + return result; +} + + +/* This is called after the TYPE and possible quote commands have been sent */ +static CURLcode ftp_state_ul_setup(struct connectdata *conn, + bool sizechecked) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + struct SessionHandle *data = conn->data; + curl_off_t passed=0; + + if((data->reqdata.resume_from && !sizechecked) || + ((data->reqdata.resume_from > 0) && sizechecked)) { + /* 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 + 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 */ + /* 4. lower the infilesize counter */ + /* => transfer as usual */ + + if(data->reqdata.resume_from < 0 ) { + /* Got no given size to start from, figure it out */ + NBFTPSENDF(conn, "SIZE %s", ftp->file); + state(conn, FTP_STOR_SIZE); + return result; + } + + /* enable append */ + data->set.ftp_append = TRUE; + + /* Let's read off the proper amount of bytes from the input. If we knew it + was a proper file we could've just fseek()ed but we only have a stream + here */ + + /* TODO: allow the ioctlfunction to provide a fast forward function that + can be used here and use this method only as a fallback! */ + do { + curl_off_t readthisamountnow = (data->reqdata.resume_from - passed); + curl_off_t actuallyread; + + if(readthisamountnow > BUFSIZE) + readthisamountnow = BUFSIZE; + + actuallyread = (curl_off_t) + conn->fread(data->state.buffer, 1, (size_t)readthisamountnow, + conn->fread_in); + + passed += actuallyread; + if(actuallyread != readthisamountnow) { + failf(data, "Could only read %" FORMAT_OFF_T + " bytes from the input", passed); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed != data->reqdata.resume_from); + + /* now, decrease the size of the read */ + if(data->set.infilesize>0) { + data->set.infilesize -= data->reqdata.resume_from; + + if(data->set.infilesize <= 0) { + infof(data, "File already completely uploaded\n"); + + /* no data to transfer */ + result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + + /* Set no_transfer so that we won't get any error in + * Curl_ftp_done() because we didn't transfer anything! */ + ftp->no_transfer = TRUE; + + state(conn, FTP_STOP); + return CURLE_OK; + } + } + /* we've passed, proceed as normal */ + } /* resume_from */ + + NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s", + ftp->file); + + state(conn, FTP_STOR); + + return result; +} + +static CURLcode ftp_state_quote(struct connectdata *conn, + bool init, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + bool quote=FALSE; + struct curl_slist *item; + + switch(instate) { + case FTP_QUOTE: + default: + item = data->set.quote; + break; + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + item = data->set.prequote; + break; + case FTP_POSTQUOTE: + item = data->set.postquote; + break; + } + + if(init) + ftpc->count1 = 0; + else + ftpc->count1++; + + if(item) { + int i = 0; + + /* Skip count1 items in the linked list */ + while((i< ftpc->count1) && item) { + item = item->next; + i++; + } + if(item) { + NBFTPSENDF(conn, "%s", item->data); + state(conn, instate); + quote = TRUE; + } + } + + if(!quote) { + /* No more quote to send, continue to ... */ + switch(instate) { + case FTP_QUOTE: + default: + result = ftp_state_cwd(conn); + break; + case FTP_RETR_PREQUOTE: + if (ftp->no_transfer) + state(conn, FTP_STOP); + else { + NBFTPSENDF(conn, "SIZE %s", ftp->file); + state(conn, FTP_RETR_SIZE); + } + break; + case FTP_STOR_PREQUOTE: + result = ftp_state_ul_setup(conn, FALSE); + break; + case FTP_POSTQUOTE: + break; + } + } + + return result; +} + +static CURLcode ftp_state_pasv_resp(struct connectdata *conn, + int ftpcode) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result; + struct SessionHandle *data=conn->data; + Curl_addrinfo *conninfo; + struct Curl_dns_entry *addr=NULL; + int rc; + unsigned short connectport; /* the local port connect() should use! */ + unsigned short newport=0; /* remote port */ + bool connected; + + /* newhost must be able to hold a full IP-style address in ASCII, which + in the IPv6 case means 5*8-1 = 39 letters */ +#define NEWHOST_BUFSIZE 48 + char newhost[NEWHOST_BUFSIZE]; + char *str=&data->state.buffer[4]; /* start on the first letter */ + + if((ftpc->count1 == 0) && + (ftpcode == 229)) { + /* positive EPSV response */ + char *ptr = strchr(str, '('); + if(ptr) { + unsigned int num; + char separator[4]; + ptr++; + if(5 == sscanf(ptr, "%c%c%c%u%c", + &separator[0], + &separator[1], + &separator[2], + &num, + &separator[3])) { + const char sep1 = separator[0]; + int i; + + /* The four separators should be identical, or else this is an oddly + formatted reply and we bail out immediately. */ + for(i=1; i<4; i++) { + if(separator[i] != sep1) { + ptr=NULL; /* set to NULL to signal error */ + break; + } + } + if(ptr) { + newport = num; + + if (conn->bits.tunnel_proxy) + /* proxy tunnel -> use other host info because ip_addr_str is the + proxy address not the ftp host */ + snprintf(newhost, sizeof(newhost), "%s", conn->host.name); + else + /* use the same IP we are already connected to */ + snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str); + } + } + else + ptr=NULL; + } + if(!ptr) { + failf(data, "Weirdly formatted EPSV reply"); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + } + else if((ftpc->count1 == 1) && + (ftpcode == 227)) { + /* positive PASV response */ + int ip[4]; + int port[2]; + + /* + * Scan for a sequence of six comma-separated numbers and use them as + * IP+port indicators. + * + * Found reply-strings include: + * "227 Entering Passive Mode (127,0,0,1,4,51)" + * "227 Data transfer will passively listen to 127,0,0,1,4,51" + * "227 Entering passive mode. 127,0,0,1,4,51" + */ + while(*str) { + if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d", + &ip[0], &ip[1], &ip[2], &ip[3], + &port[0], &port[1])) + break; + str++; + } + + if(!*str) { + failf(data, "Couldn't interpret the 227-response"); + return CURLE_FTP_WEIRD_227_FORMAT; + } + + /* we got OK from server */ + if(data->set.ftp_skip_ip) { + /* told to ignore the remotely given IP but instead use the one we used + for the control connection */ + infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n", + ip[0], ip[1], ip[2], ip[3], + conn->ip_addr_str); + if (conn->bits.tunnel_proxy) + /* proxy tunnel -> use other host info because ip_addr_str is the + proxy address not the ftp host */ + snprintf(newhost, sizeof(newhost), "%s", conn->host.name); + else + snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str); + } + else + snprintf(newhost, sizeof(newhost), + "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + newport = (port[0]<<8) + port[1]; + } + else if(ftpc->count1 == 0) { + /* EPSV failed, move on to PASV */ + + /* disable it for next transfer */ + conn->bits.ftp_use_epsv = FALSE; + infof(data, "disabling EPSV usage\n"); + + NBFTPSENDF(conn, "PASV", NULL); + ftpc->count1++; + /* remain in the FTP_PASV state */ + return result; + } + else { + failf(data, "Bad PASV/EPSV response: %03d", ftpcode); + return CURLE_FTP_WEIRD_PASV_REPLY; + } + + if(data->set.proxy && *data->set.proxy) { + /* + * This is a tunnel through a http proxy and we need to connect to the + * proxy again 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! + */ + rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING */ + rc = Curl_wait_for_resolv(conn, &addr); + + connectport = + (unsigned short)conn->port; /* we connect to the proxy's port */ + + } + else { + /* normal, direct, ftp connection */ + rc = Curl_resolv(conn, newhost, newport, &addr); + if(rc == CURLRESOLV_PENDING) + /* BLOCKING */ + rc = Curl_wait_for_resolv(conn, &addr); + + if(!addr) { + failf(data, "Can't resolve new host %s:%d", newhost, newport); + return CURLE_FTP_CANT_GET_HOST; + } + connectport = newport; /* we connect to the remote port */ + } + + result = Curl_connecthost(conn, + addr, + &conn->sock[SECONDARYSOCKET], + &conninfo, + &connected); + + Curl_resolv_unlock(data, addr); /* we're done using this address */ + + if (result && ftpc->count1 == 0 && ftpcode == 229) { + infof(data, "got positive EPSV response, but can't connect. " + "Disabling EPSV\n"); + /* disable it for next transfer */ + conn->bits.ftp_use_epsv = FALSE; + data->state.errorbuf = FALSE; /* allow error message to get rewritten */ + NBFTPSENDF(conn, "PASV", NULL); + ftpc->count1++; + /* remain in the FTP_PASV state */ + return result; + } + + if(result) + return result; + + conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */ + + /* + * When this is used from the multi interface, this might've returned with + * the 'connected' set to FALSE and thus we are now awaiting a non-blocking + * connect to connect and we should not be "hanging" here waiting. + */ + + if(data->set.verbose) + /* this just dumps information about this second connection */ + ftp_pasv_verbose(conn, conninfo, newhost, connectport); + +#ifndef CURL_DISABLE_HTTP + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { + /* FIX: this MUST wait for a proper connect first if 'connected' is + * FALSE */ + + /* BLOCKING */ + /* We want "seamless" FTP operations through HTTP proxy tunnel */ + + /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member + * conn->proto.http; we want FTP through HTTP and we have to change the + * member temporarily for connecting to the HTTP proxy. After + * Curl_proxyCONNECT we have to set back the member to the original struct + * FTP pointer + */ + struct HTTP http_proxy; + struct FTP *ftp_save = data->reqdata.proto.ftp; + memset(&http_proxy, 0, sizeof(http_proxy)); + data->reqdata.proto.http = &http_proxy; + + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport); + + data->reqdata.proto.ftp = ftp_save; + + if(CURLE_OK != result) + return result; + } +#endif /* CURL_DISABLE_HTTP */ + + state(conn, FTP_STOP); /* this phase is completed */ + + return result; +} + +static CURLcode ftp_state_port_resp(struct connectdata *conn, + int ftpcode) +{ + struct SessionHandle *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + ftpport fcmd = (ftpport)ftpc->count1; + CURLcode result = CURLE_OK; + + if(ftpcode != 200) { + /* the command failed */ + + if (EPRT == fcmd) { + infof(data, "disabling EPRT usage\n"); + conn->bits.ftp_use_eprt = FALSE; + } + fcmd++; + + if(fcmd == DONE) { + failf(data, "Failed to do PORT"); + result = CURLE_FTP_PORT_FAILED; + } + else + /* try next */ + result = ftp_state_use_port(conn, fcmd); + } + else { + infof(data, "Connect data stream actively\n"); + state(conn, FTP_STOP); /* end of DO phase */ + } + + return result; +} + +static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, + int ftpcode) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data=conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + + switch(ftpcode) { + case 213: + { + /* 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; + char *buf = data->state.buffer; + if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d", + &year, &month, &day, &hour, &minute, &second)) { + /* we have a time, reformat it */ + time_t secs=time(NULL); + /* using the good old yacc/bison yuck */ + snprintf(buf, sizeof(conn->data->state.buffer), + "%04d%02d%02d %02d:%02d:%02d GMT", + year, month, day, hour, minute, second); + /* now, convert this into a time() value: */ + data->info.filetime = (long)curl_getdate(buf, &secs); + } + + /* If we asked for a time of the file and we actually got one as well, + we "emulate" a HTTP-style header in our output. */ + + if(conn->bits.no_body && + data->set.include_header && + ftp->file && + data->set.get_filetime && + (data->info.filetime>=0) ) { + struct tm *tm; + time_t clock = (time_t)data->info.filetime; +#ifdef HAVE_GMTIME_R + struct tm buffer; + tm = (struct tm *)gmtime_r(&clock, &buffer); +#else + tm = gmtime(&clock); +#endif + /* format: "Tue, 15 Nov 1994 12:45:26" */ + snprintf(buf, BUFSIZE-1, + "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); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(result) + return result; + } /* end of a ridiculous amount of conditionals */ + } + break; + default: + infof(data, "unsupported MDTM reply format\n"); + break; + case 550: /* "No such file or directory" */ + failf(data, "Given file does not exist"); + result = CURLE_FTP_COULDNT_RETR_FILE; + break; + } + + if(data->set.timecondition) { + if((data->info.filetime > 0) && (data->set.timevalue > 0)) { + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + if(data->info.filetime <= data->set.timevalue) { + infof(data, "The requested document is not new enough\n"); + ftp->no_transfer = TRUE; /* mark this to not transfer data */ + state(conn, FTP_STOP); + return CURLE_OK; + } + break; + case CURL_TIMECOND_IFUNMODSINCE: + if(data->info.filetime > data->set.timevalue) { + infof(data, "The requested document is not old enough\n"); + ftp->no_transfer = TRUE; /* mark this to not transfer data */ + state(conn, FTP_STOP); + return CURLE_OK; + } + break; + } /* switch */ + } + else { + infof(data, "Skipping time comparison\n"); + } + } + + if(!result) + result = ftp_state_post_mdtm(conn); + + return result; +} + +static CURLcode ftp_state_type_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data=conn->data; + + if(ftpcode/100 != 2) { + /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a + successful 'TYPE I'. While that is not as RFC959 says, it is still a + positive response code and we allow that. */ + failf(data, "Couldn't set desired mode"); + return CURLE_FTP_COULDNT_SET_BINARY; /* FIX */ + } + if(ftpcode != 200) + infof(data, "Got a %03d response code instead of the assumed 200\n", + ftpcode); + + if(instate == FTP_TYPE) + result = ftp_state_post_type(conn); + else if(instate == FTP_LIST_TYPE) + result = ftp_state_post_listtype(conn); + else if(instate == FTP_RETR_TYPE) + result = ftp_state_post_retrtype(conn); + else if(instate == FTP_STOR_TYPE) + result = ftp_state_post_stortype(conn); + + return result; +} + +static CURLcode ftp_state_post_retr_size(struct connectdata *conn, + curl_off_t filesize) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data=conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + + if (data->set.max_filesize && (filesize > data->set.max_filesize)) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + ftp->downloadsize = filesize; + + if(data->reqdata.resume_from) { + /* 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 doesn't support SIZE\n"); + /* 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 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->reqdata.resume_from< 0) { + /* We're supposed to download the last abs(from) bytes */ + if(filesize < -data->reqdata.resume_from) { + failf(data, "Offset (%" FORMAT_OFF_T + ") was beyond file size (%" FORMAT_OFF_T ")", + data->reqdata.resume_from, filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* convert to size to download */ + ftp->downloadsize = -data->reqdata.resume_from; + /* download from where? */ + data->reqdata.resume_from = filesize - ftp->downloadsize; + } + else { + if(filesize < data->reqdata.resume_from) { + failf(data, "Offset (%" FORMAT_OFF_T + ") was beyond file size (%" FORMAT_OFF_T ")", + data->reqdata.resume_from, filesize); + return CURLE_BAD_DOWNLOAD_RESUME; + } + /* Now store the number of bytes we are expected to download */ + ftp->downloadsize = filesize-data->reqdata.resume_from; + } + } + + if(ftp->downloadsize == 0) { + /* no data to transfer */ + result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + infof(data, "File already completely downloaded\n"); + + /* Set no_transfer so that we won't get any error in Curl_ftp_done() + * because we didn't transfer the any file */ + ftp->no_transfer = TRUE; + state(conn, FTP_STOP); + return CURLE_OK; + } + + /* Set resume file transfer offset */ + infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T + "\n", data->reqdata.resume_from); + + NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->reqdata.resume_from); + + state(conn, FTP_RETR_REST); + + } + else { + /* no resume */ + NBFTPSENDF(conn, "RETR %s", ftp->file); + state(conn, FTP_RETR); + } + + return result; +} + +static CURLcode ftp_state_size_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data=conn->data; + curl_off_t filesize; + char *buf = data->state.buffer; + + /* get the size from the ascii string: */ + filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1; + + if(instate == FTP_SIZE) { + if(-1 != filesize) { + snprintf(buf, sizeof(data->state.buffer), + "Content-Length: %" FORMAT_OFF_T "\r\n", filesize); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(result) + return result; + } + result = ftp_state_post_size(conn); + } + else if(instate == FTP_RETR_SIZE) + result = ftp_state_post_retr_size(conn, filesize); + else if(instate == FTP_STOR_SIZE) { + data->reqdata.resume_from = filesize; + result = ftp_state_ul_setup(conn, TRUE); + } + + return result; +} + +static CURLcode ftp_state_rest_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + + switch(instate) { + case FTP_REST: + default: + if (ftpcode == 350) { + result = Curl_client_write(conn, CLIENTWRITE_BOTH, + (char *)"Accept-ranges: bytes\r\n", 0); + if(result) + return result; + } + + result = ftp_state_post_rest(conn); + break; + + case FTP_RETR_REST: + if (ftpcode != 350) { + failf(conn->data, "Couldn't use REST"); + result = CURLE_FTP_COULDNT_USE_REST; + } + else { + NBFTPSENDF(conn, "RETR %s", ftp->file); + state(conn, FTP_RETR); + } + break; + } + + return result; +} + +static CURLcode ftp_state_stor_resp(struct connectdata *conn, + int ftpcode) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + + if(ftpcode>=400) { + failf(data, "Failed FTP upload: %0d", ftpcode); + /* oops, we never close the sockets! */ + return CURLE_FTP_COULDNT_STOR_FILE; + } + + if(data->set.ftp_use_port) { + /* BLOCKING */ + /* PORT means we are now awaiting the server to connect to us. */ + result = AllowServerConnect(conn); + if( result ) + return result; + } + + if(conn->ssl[SECONDARYSOCKET].use) { + /* since we only have a plaintext TCP connection here, we must now + do the TLS stuff */ + infof(data, "Doing the SSL/TLS handshake on the data stream\n"); + /* BLOCKING */ + result = Curl_ssl_connect(conn, SECONDARYSOCKET); + if(result) + return result; + } + + *(ftp->bytecountp)=0; + + /* When we know we're uploading a specified file, we can get the file + size prior to the actual upload. */ + + Curl_pgrsSetUploadSize(data, data->set.infilesize); + + result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ + SECONDARYSOCKET, ftp->bytecountp); + state(conn, FTP_STOP); + + return result; +} + +/* for LIST and RETR responses */ +static CURLcode ftp_state_get_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + char *buf = data->state.buffer; + + if((ftpcode == 150) || (ftpcode == 125)) { + + /* + A; + 150 Opening BINARY mode data connection for /etc/passwd (2241 + bytes). (ok, the file is being transfered) + + B: + 150 Opening ASCII mode data connection for /bin/ls + + C: + 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). + + D: + 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes). + + E: + 125 Data connection already open; Transfer starting. */ + + curl_off_t size=-1; /* default unknown size */ + + + /* + * It appears that there are FTP-servers that return size 0 for files when + * SIZE is used on the file while being in BINARY mode. To work around + * that (stupid) behavior, we attempt to parse the RETR response even if + * the SIZE returned size zero. + * + * Debugging help from Salvatore Sorrentino on February 26, 2003. + */ + + if((instate != FTP_LIST) && + !data->set.prefer_ascii && + (ftp->downloadsize < 1)) { + /* + * 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 transfered 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; + bytes=strstr(buf, " bytes"); + if(bytes--) { + long in=(long)(bytes-buf); + /* this is a hint there is size information in there! ;-) */ + while(--in) { + /* scan for the left parenthesis and break there */ + if('(' == *bytes) + break; + /* skip only digits */ + if(!ISDIGIT(*bytes)) { + bytes=NULL; + break; + } + /* one more estep backwards */ + bytes--; + } + /* if we have nothing but digits: */ + if(bytes++) { + /* get the number! */ + size = curlx_strtoofft(bytes, NULL, 0); + } + } + } + else if(ftp->downloadsize > -1) + size = ftp->downloadsize; + + if(data->set.ftp_use_port) { + /* BLOCKING */ + result = AllowServerConnect(conn); + if( result ) + return result; + } + + if(conn->ssl[SECONDARYSOCKET].use) { + /* since we only have a plaintext TCP connection here, we must now + do the TLS stuff */ + infof(data, "Doing the SSL/TLS handshake on the data stream\n"); + result = Curl_ssl_connect(conn, SECONDARYSOCKET); + if(result) + return result; + } + + if(size > data->reqdata.maxdownload && data->reqdata.maxdownload > 0) + size = data->reqdata.size = data->reqdata.maxdownload; + + infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->reqdata.maxdownload); + + if(instate != FTP_LIST) + infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size); + + /* FTP download: */ + result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE, + ftp->bytecountp, + -1, NULL); /* no upload here */ + if(result) + return result; + + state(conn, FTP_STOP); + } + else { + if((instate == FTP_LIST) && (ftpcode == 450)) { + /* simply no matching files in the dir listing */ + ftp->no_transfer = TRUE; /* don't download anything */ + state(conn, FTP_STOP); /* this phase is over */ + } + else { + failf(data, "RETR response: %03d", ftpcode); + return CURLE_FTP_COULDNT_RETR_FILE; + } + } + + return result; +} + +/* after USER, PASS and ACCT */ +static CURLcode ftp_state_loggedin(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + +#ifdef HAVE_KRB4 + if(conn->data->set.krb4) { + /* We are logged in, asked to use Kerberos. Set the requested + * protection level + */ + if(conn->sec_complete) + /* BLOCKING */ + Curl_sec_set_protection_level(conn); + + /* We may need to issue a KAUTH here to have access to the files + * do it if user supplied a password + */ + if(conn->passwd && *conn->passwd) { + /* BLOCKING */ + result = Curl_krb_kauth(conn); + if(result) + return result; + } + } +#endif + if(conn->ssl[FIRSTSOCKET].use) { + /* PBSZ = PROTECTION BUFFER SIZE. + + The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: + + Specifically, the PROT command MUST be preceded by a PBSZ + command and a PBSZ command MUST be preceded by a successful + security data exchange (the TLS negotiation in this case) + + ... (and on page 8): + + Thus the PBSZ command must still be issued, but must have a + parameter of '0' to indicate that no buffering is taking place + and the data connection should not be encapsulated. + */ + NBFTPSENDF(conn, "PBSZ %d", 0); + state(conn, FTP_PBSZ); + } + else { + result = ftp_state_pwd(conn); + } + return result; +} + +/* for USER and PASS responses */ +static CURLcode ftp_state_user_resp(struct connectdata *conn, + int ftpcode, + ftpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + (void)instate; /* no use for this yet */ + + if((ftpcode == 331) && (ftpc->state == FTP_USER)) { + /* 331 Password required for ... + (the server requires to send the user's password too) */ + NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:""); + state(conn, FTP_PASS); + } + else if(ftpcode/100 == 2) { + /* 230 User ... logged in. + (the user logged in with or without password) */ + result = ftp_state_loggedin(conn); + } + else if(ftpcode == 332) { + if(data->set.ftp_account) { + NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account); + state(conn, FTP_ACCT); + } + else { + failf(data, "ACCT requested but none available"); + result = CURLE_LOGIN_DENIED; + } + } + else { + /* All other response codes, like: + + 530 User ... access denied + (the server denies to log the specified user) */ + + if (conn->data->set.ftp_alternative_to_user && + !conn->data->state.ftp_trying_alternative) { + /* Ok, USER failed. Let's try the supplied command. */ + NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user); + conn->data->state.ftp_trying_alternative = TRUE; + state(conn, FTP_USER); + result = CURLE_OK; + } + else { + failf(data, "Access denied: %03d", ftpcode); + result = CURLE_LOGIN_DENIED; + } + } + return result; +} + +/* for ACCT response */ +static CURLcode ftp_state_acct_resp(struct connectdata *conn, + int ftpcode) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + if(ftpcode != 230) { + failf(data, "ACCT rejected by server: %03d", ftpcode); + result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ + } + else + result = ftp_state_loggedin(conn); + + return result; +} + + +static CURLcode ftp_statemach_act(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + struct SessionHandle *data=conn->data; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + static const char * const ftpauth[] = { + "SSL", "TLS" + }; + size_t nread = 0; + + if(ftpc->sendleft) { + /* we have a piece of a command still left to send */ + ssize_t written; + result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize - + ftpc->sendleft, ftpc->sendleft, &written); + if(result) + return result; + + if(written != (ssize_t)ftpc->sendleft) { + /* only a fraction was sent */ + ftpc->sendleft -= written; + } + else { + free(ftpc->sendthis); + ftpc->sendthis=NULL; + ftpc->sendleft = ftpc->sendsize = 0; + ftpc->response = Curl_tvnow(); + } + return CURLE_OK; + } + + /* we read a piece of response */ + result = ftp_readresp(sock, conn, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode != 220) { + failf(data, "This doesn't seem like a nice ftp-server response"); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_KRB4 + if(data->set.krb4) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.krb4_level); + + if(Curl_sec_login(conn) != 0) + infof(data, "Logging in with password in cleartext!\n"); + else + infof(data, "Authentication successful\n"); + } +#endif + + if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3=0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n", + data->set.ftpsslauth); + return CURLE_FAILED_INIT; /* we don't know what to do */ + } + NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]); + state(conn, FTP_AUTH); + } + else { + result = ftp_state_user(conn); + if(result) + return result; + } + + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(CURLE_OK == result) { + conn->protocol |= PROT_FTPS; + conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ + result = ftp_state_user(conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.ftp_ssl > CURLFTPSSL_TRY) + /* we failed and CURLFTPSSL_CONTROL or CURLFTPSSL_ALL is set */ + result = CURLE_FTP_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(conn); + } + + if(result) + return result; + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(conn, ftpcode); + break; + + case FTP_PBSZ: + /* FIX: check response code */ + + /* For TLS, the data connection can have one of two security levels. + + 1) Clear (requested by 'PROT C') + + 2)Private (requested by 'PROT P') + */ + if(!conn->ssl[SECONDARYSOCKET].use) { + NBFTPSENDF(conn, "PROT %c", + data->set.ftp_ssl == CURLFTPSSL_CONTROL ? 'C' : 'P'); + state(conn, FTP_PROT); + } + else { + result = ftp_state_pwd(conn); + if(result) + return result; + } + + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->ssl[SECONDARYSOCKET].use = + (bool)(data->set.ftp_ssl != CURLFTPSSL_CONTROL); + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL) + /* we failed and bails out */ + return CURLE_FTP_SSL_FAILED; + + if(data->set.ftp_use_ccc) { + /* CCC - Clear Command Channel + */ + NBFTPSENDF(conn, "CCC", NULL); + state(conn, FTP_CCC); + } + else { + result = ftp_state_pwd(conn); + if(result) + return result; + } + break; + + case FTP_CCC: + if (ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(conn, FIRSTSOCKET); + + if(result) { + failf(conn->data, "Failed to clear the command channel (CCC)"); + return result; + } + } + + /* Then continue as normal */ + result = ftp_state_pwd(conn); + if(result) + return result; + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *dir = (char *)malloc(nread+1); + char *store=dir; + char *ptr=&data->state.buffer[4]; /* start on the first letter */ + + if(!dir) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 257"" and the RFC959 + says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + if('\"' == *ptr) { + /* it started good */ + ptr++; + while(ptr && *ptr) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + *store = ptr[1]; + ptr++; + } + else { + /* end of path */ + *store = '\0'; /* zero terminate */ + break; /* get out of this loop */ + } + } + else + *store = *ptr; + store++; + ptr++; + } + ftpc->entrypath =dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path\n"); + } + } + state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE\n")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if(ftpcode >= 400) { + failf(conn->data, "QUOT command failed with %03d", ftpcode); + return CURLE_FTP_QUOTE_ERROR; + } + result = ftp_state_quote(conn, FALSE, ftpc->state); + if(result) + return result; + + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(conn->data->set.ftp_create_missing_dirs && + ftpc->count1 && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]); + state(conn, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + return CURLE_FTP_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2=0; + if(++ftpc->count1 <= ftpc->dirdepth) { + /* send next CWD */ + NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + } + else { + result = ftp_state_post_cwd(conn); + if(result) + return result; + } + } + break; + + case FTP_MKD: + if(ftpcode/100 != 2) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + return CURLE_FTP_ACCESS_DENIED; + } + state(conn, FTP_CWD); + /* send CWD */ + NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(conn, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(conn, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(conn, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(conn, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(conn, ftpcode); + break; + + case FTP_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(conn, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} + +/* Returns timeout in ms. 0 or negative number means the timeout has already + triggered */ +static long ftp_state_timeout(struct connectdata *conn) +{ + struct SessionHandle *data=conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + long timeout_ms=360000; /* in milliseconds */ + + if(data->set.ftp_response_timeout ) + /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining + time. Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed + to govern the response for any given ftp response, not for the time + from connect to the given ftp response. */ + timeout_ms = data->set.ftp_response_timeout*1000 - /* timeout time */ + Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */ + else if(data->set.timeout) + /* if timeout is requested, find out how much remaining time we have */ + timeout_ms = data->set.timeout*1000 - /* timeout time */ + Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ + else + /* Without a requested timeout, we only wait 'response_time' seconds for + the full response to arrive before we bail out */ + timeout_ms = ftpc->response_time*1000 - + Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */ + + return timeout_ms; +} + + +/* called repeatedly until done from multi.c */ +CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, + bool *done) +{ + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc; + struct SessionHandle *data=conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + long timeout_ms = ftp_state_timeout(conn); + + *done = FALSE; /* default to not done yet */ + + if(timeout_ms <= 0) { + failf(data, "FTP response timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + rc = Curl_select(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */ + 0); + + if(rc == -1) { + failf(data, "select error"); + return CURLE_OUT_OF_MEMORY; + } + else if(rc != 0) { + result = ftp_statemach_act(conn); + *done = (bool)(ftpc->state == FTP_STOP); + } + /* if rc == 0, then select() timed out */ + + return result; +} + +static CURLcode ftp_easy_statemach(struct connectdata *conn) +{ + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int rc; + struct SessionHandle *data=conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result = CURLE_OK; + + while(ftpc->state != FTP_STOP) { + long timeout_ms = ftp_state_timeout(conn); + + if(timeout_ms <=0 ) { + failf(data, "FTP response timeout"); + return CURLE_OPERATION_TIMEDOUT; /* already too little time */ + } + + rc = Curl_select(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */ + (int)timeout_ms); + + if(rc == -1) { + failf(data, "select error"); + return CURLE_OUT_OF_MEMORY; + } + else if(rc == 0) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } + else { + result = ftp_statemach_act(conn); + if(result) + break; + } + } + + return result; +} + +/* + * Allocate and initialize the struct FTP for the current SessionHandle. If + * need be. + */ +static CURLcode ftp_init(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + struct FTP *ftp; + if(data->reqdata.proto.ftp) + return CURLE_OK; + + ftp = (struct FTP *)calloc(sizeof(struct FTP), 1); + if(!ftp) + return CURLE_OUT_OF_MEMORY; + + data->reqdata.proto.ftp = ftp; + + /* get some initial data into the ftp struct */ + ftp->bytecountp = &data->reqdata.keep.bytecount; + + /* no need to duplicate them, this connectdata struct won't change */ + ftp->user = conn->user; + ftp->passwd = conn->passwd; + if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd)) + return CURLE_URL_MALFORMAT; + + return CURLE_OK; +} + +/* + * Curl_ftp_connect() should do everything that is to be considered a part of + * the connection phase. + * + * The variable 'done' points to will be TRUE if the protocol-layer connect + * phase is done when this function returns, or FALSE is not. When called as + * a part of the easy interface, it will always be TRUE. + */ +CURLcode Curl_ftp_connect(struct connectdata *conn, + bool *done) /* see description above */ +{ + CURLcode result; +#ifndef CURL_DISABLE_HTTP + /* for FTP over HTTP proxy */ + struct HTTP http_proxy; + struct FTP *ftp_save; +#endif /* CURL_DISABLE_HTTP */ + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct SessionHandle *data=conn->data; + + *done = FALSE; /* default to not done yet */ + + if (data->reqdata.proto.ftp) { + Curl_ftp_disconnect(conn); + free(data->reqdata.proto.ftp); + data->reqdata.proto.ftp = NULL; + } + + result = ftp_init(conn); + if(result) + return result; + + /* We always support persistant connections on ftp */ + conn->bits.close = FALSE; + + ftpc->response_time = 3600; /* set default response time-out */ + +#ifndef CURL_DISABLE_HTTP + if (conn->bits.tunnel_proxy && conn->bits.httpproxy) { + /* BLOCKING */ + /* We want "seamless" FTP operations through HTTP proxy tunnel */ + + /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member + * conn->proto.http; we want FTP through HTTP and we have to change the + * member temporarily for connecting to the HTTP proxy. After + * Curl_proxyCONNECT we have to set back the member to the original struct + * FTP pointer + */ + ftp_save = data->reqdata.proto.ftp; + memset(&http_proxy, 0, sizeof(http_proxy)); + data->reqdata.proto.http = &http_proxy; + + result = Curl_proxyCONNECT(conn, FIRSTSOCKET, + conn->host.name, conn->remote_port); + + data->reqdata.proto.ftp = ftp_save; + + if(CURLE_OK != result) + return result; + } +#endif /* CURL_DISABLE_HTTP */ + + if(conn->protocol & PROT_FTPS) { + /* BLOCKING */ + /* FTPS is simply ftp with SSL for the control channel */ + /* now, perform the SSL initialization for this socket */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(result) + return result; + } + + /* When we connect, we start in the state where we await the 220 + response */ + ftp_respinit(conn); /* init the response reader stuff */ + state(conn, FTP_WAIT220); + ftpc->response = Curl_tvnow(); /* start response time-out now! */ + + if(data->state.used_interface == Curl_if_multi) + result = Curl_ftp_multi_statemach(conn, done); + else { + result = ftp_easy_statemach(conn); + if(!result) + *done = TRUE; + } + + return result; +} + +/*********************************************************************** + * + * Curl_ftp_done() + * + * The DONE function. This does what needs to be done after a single DO has + * performed. + * + * Input argument is already checked for validity. + */ +CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature) +{ + struct SessionHandle *data = conn->data; + struct FTP *ftp = data->reqdata.proto.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + ssize_t nread; + int ftpcode; + CURLcode result=CURLE_OK; + bool was_ctl_valid = ftpc->ctl_valid; + size_t flen; + size_t dlen; + char *path; + char *path_to_use = data->reqdata.path; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + + if(!ftp) + /* When the easy handle is removed from the multi while libcurl is still + * trying to resolve the host name, it seems that the ftp struct is not + * yet initialized, but the removal action calls Curl_done() which calls + * this function. So we simply return success if no ftp pointer is set. + */ + return CURLE_OK; + + switch(status) { + case CURLE_BAD_DOWNLOAD_RESUME: + case CURLE_FTP_WEIRD_PASV_REPLY: + case CURLE_FTP_PORT_FAILED: + case CURLE_FTP_COULDNT_SET_BINARY: + case CURLE_FTP_COULDNT_RETR_FILE: + case CURLE_FTP_COULDNT_STOR_FILE: + case CURLE_FTP_ACCESS_DENIED: + /* the connection stays alive fine even though this happened */ + /* fall-through */ + case CURLE_OK: /* doesn't affect the control connection's status */ + if (!premature) { + ftpc->ctl_valid = was_ctl_valid; + break; + } + /* until we cope better with prematurely ended requests, let them + * fallback as if in complete failure */ + default: /* by default, an error means the control connection is + wedged and should not be used anymore */ + ftpc->ctl_valid = FALSE; + ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the + current path, as this connection is going */ + conn->bits.close = TRUE; /* marked for closure */ + break; + } + + /* now store a copy of the directory we are in */ + if(ftpc->prevpath) + free(ftpc->prevpath); + + /* get the "raw" path */ + path = curl_easy_unescape(data, path_to_use, 0, NULL); + if(!path) + return CURLE_OUT_OF_MEMORY; + + flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */ + dlen = strlen(path)-flen; + if(dlen && !ftpc->cwdfail) { + ftpc->prevpath = path; + if(flen) + /* if 'path' is not the whole string */ + ftpc->prevpath[dlen]=0; /* terminate */ + infof(data, "Remembering we are in dir %s\n", ftpc->prevpath); + } + else { + ftpc->prevpath = NULL; /* no path */ + free(path); + } + /* free the dir tree and file parts */ + freedirs(conn); + +#ifdef HAVE_KRB4 + Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]); +#endif + + /* shut down the socket to inform the server we're done */ + +#ifdef _WIN32_WCE + shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */ +#endif + + sclose(conn->sock[SECONDARYSOCKET]); + + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + + if(!ftp->no_transfer && !status && !premature) { + /* + * Let's see what the server says about the transfer we just performed, + * but lower the timeout as sometimes this connection has died while the + * data has been transfered. This happens when doing through NATs etc that + * abandon old silent connections. + */ + long old_time = ftpc->response_time; + + ftpc->response_time = 60; /* give it only a minute for now */ + + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + + ftpc->response_time = old_time; /* set this back to previous value */ + + if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { + failf(data, "control connection looks dead"); + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + return result; + } + + if(result) + return result; + + if(!ftpc->dont_check) { + /* 226 Transfer complete, 250 Requested file action okay, completed. */ + if((ftpcode != 226) && (ftpcode != 250)) { + failf(data, "server did not report OK, got %d", ftpcode); + result = CURLE_PARTIAL_FILE; + } + } + } + + if(result || premature) + /* the response code from the transfer showed an error already so no + use checking further */ + ; + else if(data->set.upload) { + if((-1 != data->set.infilesize) && + (data->set.infilesize != *ftp->bytecountp) && + !data->set.crlf && + !ftp->no_transfer) { + failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T + " out of %" FORMAT_OFF_T " bytes)", + *ftp->bytecountp, data->set.infilesize); + result = CURLE_PARTIAL_FILE; + } + } + else { + if((-1 != k->size) && (k->size != *ftp->bytecountp) && +#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->size + data->state.crlf_conversions) != *ftp->bytecountp) && +#endif /* CURL_DO_LINEEND_CONV */ + (k->maxdownload != *ftp->bytecountp)) { + failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes", + *ftp->bytecountp); + result = CURLE_PARTIAL_FILE; + } + else if(!ftpc->dont_check && + !*ftp->bytecountp && + (k->size>0)) { + failf(data, "No data was received!"); + result = CURLE_FTP_COULDNT_RETR_FILE; + } + } + + /* clear these for next connection */ + ftp->no_transfer = FALSE; + ftpc->dont_check = FALSE; + + /* Send any post-transfer QUOTE strings? */ + if(!status && !result && !premature && data->set.postquote) + result = ftp_sendquote(conn, data->set.postquote); + + return result; +} + +/*********************************************************************** + * + * ftp_sendquote() + * + * Where a 'quote' means a list of custom commands to send to the server. + * The quote list is passed as an argument. + */ + +static +CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) +{ + struct curl_slist *item; + ssize_t nread; + int ftpcode; + CURLcode result; + + item = quote; + while (item) { + if (item->data) { + FTPSENDF(conn, "%s", item->data); + + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if (result) + return result; + + if (ftpcode >= 400) { + failf(conn->data, "QUOT string not accepted: %s", item->data); + return CURLE_FTP_QUOTE_ERROR; + } + } + + item = item->next; + } + + return CURLE_OK; +} + +/*********************************************************************** + * + * ftp_need_type() + * + * Returns TRUE if we in the current situation should send TYPE + */ +static int ftp_need_type(struct connectdata *conn, + bool ascii_wanted) +{ + return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); +} + +/*********************************************************************** + * + * ftp_nb_type() + * + * Set TYPE. We only deal with ASCII or BINARY so this function + * sets one of them. + * If the transfer type is not sent, simulate on OK response in newstate + */ +static CURLcode ftp_nb_type(struct connectdata *conn, + bool ascii, ftpstate newstate) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + CURLcode result; + int want = ascii?'A':'I'; + + if (ftpc->transfertype == want) { + state(conn, newstate); + return ftp_state_type_resp(conn, 200, newstate); + } + + NBFTPSENDF(conn, "TYPE %c", want); + state(conn, newstate); + + /* keep track of our current transfer type */ + ftpc->transfertype = want; + return CURLE_OK; +} + +/*************************************************************************** + * + * ftp_pasv_verbose() + * + * This function only outputs some informationals about this second connection + * when we've issued a PASV command before and thus we have connected to a + * possibly new IP address. + * + */ +static void +ftp_pasv_verbose(struct connectdata *conn, + Curl_addrinfo *ai, + char *newhost, /* ascii version */ + int port) +{ + char buf[256]; + Curl_printable_address(ai, buf, sizeof(buf)); + infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port); +} + +/* + Check if this is a range download, and if so, set the internal variables + properly. + */ + +static CURLcode ftp_range(struct connectdata *conn) +{ + curl_off_t from, to; + curl_off_t totalsize=-1; + char *ptr; + char *ptr2; + struct SessionHandle *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(data->reqdata.use_range && data->reqdata.range) { + from=curlx_strtoofft(data->reqdata.range, &ptr, 0); + while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-'))) + ptr++; + to=curlx_strtoofft(ptr, &ptr2, 0); + if(ptr == ptr2) { + /* we didn't get any digit */ + to=-1; + } + if((-1 == to) && (from>=0)) { + /* X - */ + data->reqdata.resume_from = from; + DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", + from)); + } + else if(from < 0) { + /* -Y */ + totalsize = -from; + data->reqdata.maxdownload = -from; + data->reqdata.resume_from = from; + DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", + totalsize)); + } + else { + /* X-Y */ + totalsize = to-from; + data->reqdata.maxdownload = totalsize+1; /* include last byte */ + data->reqdata.resume_from = from; + DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T + " getting %" FORMAT_OFF_T " bytes\n", + from, data->reqdata.maxdownload)); + } + DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T + " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n", + from, to, data->reqdata.maxdownload)); + ftpc->dont_check = TRUE; /* dont check for successful transfer */ + } + return CURLE_OK; +} + + +/* + * Curl_ftp_nextconnect() + * + * This function shall be called when the second FTP (data) connection is + * connected. + */ + +CURLcode Curl_ftp_nextconnect(struct connectdata *conn) +{ + struct SessionHandle *data=conn->data; + CURLcode result = CURLE_OK; + + /* the ftp struct is inited in Curl_ftp_connect() */ + struct FTP *ftp = data->reqdata.proto.ftp; + + DEBUGF(infof(data, "DO-MORE phase starts\n")); + + if(!ftp->no_transfer && !conn->bits.no_body) { + /* a transfer is about to take place */ + + if(data->set.upload) { + result = ftp_nb_type(conn, data->set.prefer_ascii, + FTP_STOR_TYPE); + if (result) + return result; + } + else { + /* download */ + ftp->downloadsize = -1; /* unknown as of yet */ + + result = ftp_range(conn); + if(result) + ; + else if((data->set.ftp_list_only) || !ftp->file) { + /* The specified path ends with a slash, and therefore we think this + is a directory that is requested, use LIST. But before that we + need to set ASCII transfer mode. */ + result = ftp_nb_type(conn, 1, FTP_LIST_TYPE); + if (result) + return result; + } + else { + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE); + if (result) + return result; + } + } + result = ftp_easy_statemach(conn); + } + + if(ftp->no_transfer) + /* no data to transfer. FIX: it feels like a kludge to have this here + too! */ + result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + + /* end of transfer */ + DEBUGF(infof(data, "DO-MORE phase ends with %d\n", result)); + + return result; +} + + + +/*********************************************************************** + * + * ftp_perform() + * + * This is the actual DO function for FTP. Get a file/directory according to + * the options previously setup. + */ + +static +CURLcode ftp_perform(struct connectdata *conn, + bool *connected, /* connect status after PASV / PORT */ + bool *dophase_done) +{ + /* this is FTP and no proxy */ + CURLcode result=CURLE_OK; + + DEBUGF(infof(conn->data, "DO phase starts\n")); + + *dophase_done = FALSE; /* not done yet */ + + /* start the first command in the DO phase */ + result = ftp_state_quote(conn, TRUE, FTP_QUOTE); + if(result) + return result; + + /* run the state-machine */ + if(conn->data->state.used_interface == Curl_if_multi) + result = Curl_ftp_multi_statemach(conn, dophase_done); + else { + result = ftp_easy_statemach(conn); + *dophase_done = TRUE; /* with the easy interface we are done here */ + } + *connected = conn->bits.tcpconnect; + + if(*dophase_done) { + DEBUGF(infof(conn->data, "DO phase is complete\n")); + } + + return result; +} + +/*********************************************************************** + * + * Curl_ftp() + * + * This function is registered as 'curl_do' function. It decodes the path + * parts etc as a wrapper to the actual DO function (ftp_perform). + * + * The input argument is already checked for validity. + */ +CURLcode Curl_ftp(struct connectdata *conn, bool *done) +{ + CURLcode retcode = CURLE_OK; + + *done = FALSE; /* default to false */ + + /* + Since connections can be re-used between SessionHandles, this might be a + connection already existing but on a fresh SessionHandle struct so we must + make sure we have a good 'struct FTP' to play with. For new connections, + the struct FTP is allocated and setup in the Curl_ftp_connect() function. + */ + retcode = ftp_init(conn); + if(retcode) + return retcode; + + retcode = ftp_parse_url_path(conn); + if (retcode) + return retcode; + + retcode = ftp_regular_transfer(conn, done); + + return retcode; +} + +/*********************************************************************** + * + * Curl_(nb)ftpsendf() + * + * Sends the formated string as a ftp command to a ftp server + * + * NOTE: we build the command in a fixed-length buffer, which sets length + * restrictions on the command! + * + * The "nb" version is made to Never Block. + */ +CURLcode Curl_nbftpsendf(struct connectdata *conn, + const char *fmt, ...) +{ + ssize_t bytes_written; + char s[256]; + size_t write_len; + char *sptr=s; + CURLcode res = CURLE_OK; + struct SessionHandle *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + va_list ap; + va_start(ap, fmt); + vsnprintf(s, 250, fmt, ap); + va_end(ap); + + strcat(s, "\r\n"); /* append a trailing CRLF */ + + bytes_written=0; + write_len = strlen(s); + + ftp_respinit(conn); + +#ifdef CURL_DOES_CONVERSIONS + res = Curl_convert_to_network(data, s, write_len); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(res != CURLE_OK) { + return res; + } +#endif /* CURL_DOES_CONVERSIONS */ + + res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, + &bytes_written); + + if(CURLE_OK != res) + return res; + + if(conn->data->set.verbose) + Curl_debug(conn->data, CURLINFO_HEADER_OUT, + sptr, (size_t)bytes_written, conn); + + if(bytes_written != (ssize_t)write_len) { + /* the whole chunk was not sent, store the rest of the data */ + write_len -= bytes_written; + sptr += bytes_written; + ftpc->sendthis = malloc(write_len); + if(ftpc->sendthis) { + memcpy(ftpc->sendthis, sptr, write_len); + ftpc->sendsize = ftpc->sendleft = write_len; + } + else { + failf(data, "out of memory"); + res = CURLE_OUT_OF_MEMORY; + } + } + else + ftpc->response = Curl_tvnow(); + + return res; +} + +CURLcode Curl_ftpsendf(struct connectdata *conn, + const char *fmt, ...) +{ + ssize_t bytes_written; + char s[256]; + size_t write_len; + char *sptr=s; + CURLcode res = CURLE_OK; + + va_list ap; + va_start(ap, fmt); + vsnprintf(s, 250, fmt, ap); + va_end(ap); + + strcat(s, "\r\n"); /* append a trailing CRLF */ + + bytes_written=0; + write_len = strlen(s); + +#ifdef CURL_DOES_CONVERSIONS + res = Curl_convert_to_network(conn->data, s, write_len); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(res != CURLE_OK) { + return(res); + } +#endif /* CURL_DOES_CONVERSIONS */ + + while(1) { + res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, + &bytes_written); + + if(CURLE_OK != res) + break; + + if(conn->data->set.verbose) + Curl_debug(conn->data, CURLINFO_HEADER_OUT, + sptr, (size_t)bytes_written, conn); + + if(bytes_written != (ssize_t)write_len) { + write_len -= bytes_written; + sptr += bytes_written; + } + else + break; + } + + return res; +} + +/*********************************************************************** + * + * ftp_quit() + * + * This should be called before calling sclose() on an ftp control connection + * (not data connections). We should then wait for the response from the + * server before returning. The calling code should then try to close the + * connection. + * + */ +static CURLcode ftp_quit(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->proto.ftpc.ctl_valid) { + NBFTPSENDF(conn, "QUIT", NULL); + state(conn, FTP_QUIT); + + result = ftp_easy_statemach(conn); + } + + return result; +} + +/*********************************************************************** + * + * Curl_ftp_disconnect() + * + * Disconnect from an FTP server. Cleanup protocol-specific per-connection + * resources. BLOCKING. + */ +CURLcode Curl_ftp_disconnect(struct connectdata *conn) +{ + struct ftp_conn *ftpc= &conn->proto.ftpc; + + /* We cannot send quit unconditionally. If this connection is stale or + 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's ok it + will try to send the QUIT command, otherwise it will just return. + */ + + /* The FTP session may or may not have been allocated/setup at this point! */ + if(conn->data->reqdata.proto.ftp) { + (void)ftp_quit(conn); /* ignore errors on the QUIT */ + + if(ftpc->entrypath) { + struct SessionHandle *data = conn->data; + data->state.most_recent_ftp_entrypath = NULL; + free(ftpc->entrypath); + ftpc->entrypath = NULL; + } + if(ftpc->cache) { + free(ftpc->cache); + ftpc->cache = NULL; + } + freedirs(conn); + if(ftpc->prevpath) { + free(ftpc->prevpath); + ftpc->prevpath = NULL; + } + } + return CURLE_OK; +} + +/*********************************************************************** + * + * ftp_parse_url_path() + * + * Parse the URL path into separate path components. + * + */ +static +CURLcode ftp_parse_url_path(struct connectdata *conn) +{ + CURLcode retcode = CURLE_OK; + struct SessionHandle *data = conn->data; + /* the ftp struct is already inited in ftp_connect() */ + struct FTP *ftp = data->reqdata.proto.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + size_t dlen; + char *slash_pos; /* position of the first '/' char in curpos */ + char *path_to_use = data->reqdata.path; + char *cur_pos; + + cur_pos = path_to_use; /* current position in path. point at the begin + of next path component */ + + ftpc->ctl_valid = FALSE; + ftpc->cwdfail = FALSE; + + switch(data->set.ftp_filemethod) { + case FTPFILE_NOCWD: + /* fastest, but less standard-compliant */ + ftp->file = data->reqdata.path; /* this is a full file path */ + break; + + case FTPFILE_SINGLECWD: + /* get the last slash */ + slash_pos=strrchr(cur_pos, '/'); + if(slash_pos || !cur_pos || !*cur_pos) { + ftpc->dirdepth = 1; /* we consider it to be a single dir */ + ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0])); + if(!ftpc->dirs) + return CURLE_OUT_OF_MEMORY; + + ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", + slash_pos?(int)(slash_pos-cur_pos):1, + NULL); + if(!ftpc->dirs[0]) { + free(ftpc->dirs); + return CURLE_OUT_OF_MEMORY; + } + ftp->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ + } + else + ftp->file = cur_pos; /* this is a file name only */ + break; + + default: /* allow pretty much anything */ + case FTPFILE_MULTICWD: + ftpc->dirdepth = 0; + ftpc->diralloc = 5; /* default dir depth to allocate */ + ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0])); + if(!ftpc->dirs) + return CURLE_OUT_OF_MEMORY; + + /* parse the URL path into separate path components */ + while ((slash_pos = strchr(cur_pos, '/')) != NULL) { + /* 1 or 0 to indicate absolute directory */ + bool absolute_dir = (bool)((cur_pos - data->reqdata.path > 0) && + (ftpc->dirdepth == 0)); + + /* seek out the next path component */ + if (slash_pos-cur_pos) { + /* we skip empty path components, like "x//y" since the FTP command + CWD requires a parameter and a non-existent parameter a) doesn't + work on many servers and b) has no effect on the others. */ + int len = (int)(slash_pos - cur_pos + absolute_dir); + ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data, + cur_pos - absolute_dir, + len, NULL); + if (!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ + failf(data, "no memory"); + freedirs(conn); + return CURLE_OUT_OF_MEMORY; + } + if (isBadFtpString(ftpc->dirs[ftpc->dirdepth])) { + freedirs(conn); + return CURLE_URL_MALFORMAT; + } + } + else { + cur_pos = slash_pos + 1; /* jump to the rest of the string */ + continue; + } + + if(!retcode) { + cur_pos = slash_pos + 1; /* jump to the rest of the string */ + if(++ftpc->dirdepth >= ftpc->diralloc) { + /* enlarge array */ + char *bigger; + ftpc->diralloc *= 2; /* double the size each time */ + bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0])); + if(!bigger) { + ftpc->dirdepth--; + freedirs(conn); + return CURLE_OUT_OF_MEMORY; + } + ftpc->dirs = (char **)bigger; + } + } + } + + ftp->file = cur_pos; /* the rest is the file name */ + } + + if(*ftp->file) { + ftp->file = curl_easy_unescape(conn->data, ftp->file, 0, NULL); + if(NULL == ftp->file) { + freedirs(conn); + failf(data, "no memory"); + return CURLE_OUT_OF_MEMORY; + } + if (isBadFtpString(ftp->file)) { + freedirs(conn); + return CURLE_URL_MALFORMAT; + } + } + else + ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL + pointer */ + + if(data->set.upload && !ftp->file && + (!ftp->no_transfer || conn->bits.no_body)) { + /* We need a file name when uploading. Return error! */ + failf(data, "Uploading to a URL without a file name!"); + return CURLE_URL_MALFORMAT; + } + + ftpc->cwddone = FALSE; /* default to not done */ + + if(ftpc->prevpath) { + /* prevpath is "raw" so we convert the input path before we compare the + strings */ + char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL); + if(!path) + return CURLE_OUT_OF_MEMORY; + + dlen = strlen(path) - (ftp->file?strlen(ftp->file):0); + if((dlen == strlen(ftpc->prevpath)) && + curl_strnequal(path, ftpc->prevpath, dlen)) { + infof(data, "Request has same path as previous transfer\n"); + ftpc->cwddone = TRUE; + } + free(path); + } + + return retcode; +} + +/* call this when the DO phase has completed */ +static CURLcode ftp_dophase_done(struct connectdata *conn, + bool connected) +{ + CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->reqdata.proto.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(connected) + result = Curl_ftp_nextconnect(conn); + + if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) { + /* Failure detected, close the second socket if it was created already */ + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + return result; + } + + if(ftp->no_transfer) + /* no data to transfer */ + result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + else if(!connected) + /* since we didn't connect now, we want do_more to get called */ + conn->bits.do_more = TRUE; + + ftpc->ctl_valid = TRUE; /* seems good */ + + return result; +} + +/* called from multi.c while DOing */ +CURLcode Curl_ftp_doing(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result; + result = Curl_ftp_multi_statemach(conn, dophase_done); + + if(*dophase_done) { + result = ftp_dophase_done(conn, FALSE /* not connected */); + + DEBUGF(infof(conn->data, "DO phase is complete\n")); + } + return result; +} + +/*********************************************************************** + * + * ftp_regular_transfer() + * + * The input argument is already checked for validity. + * + * Performs all commands done before a regular transfer between a local and a + * remote host. + * + * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the + * Curl_ftp_done() function without finding any major problem. + */ +static +CURLcode ftp_regular_transfer(struct connectdata *conn, + bool *dophase_done) +{ + CURLcode result=CURLE_OK; + bool connected=0; + struct SessionHandle *data = conn->data; + struct ftp_conn *ftpc = &conn->proto.ftpc; + data->reqdata.size = -1; /* make sure this is unknown at this point */ + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + Curl_pgrsSetUploadSize(data, 0); + Curl_pgrsSetDownloadSize(data, 0); + + ftpc->ctl_valid = TRUE; /* starts good */ + + result = ftp_perform(conn, + &connected, /* have we connected after PASV/PORT */ + dophase_done); /* all commands in the DO-phase done? */ + + if(CURLE_OK == result) { + + if(!*dophase_done) + /* the DO phase has not completed yet */ + return CURLE_OK; + + result = ftp_dophase_done(conn, connected); + if(result) + return result; + } + else + freedirs(conn); + + return result; +} + +#endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h new file mode 100644 index 0000000..b64e705 --- /dev/null +++ b/Utilities/cmcurl/lib/ftp.h @@ -0,0 +1,43 @@ +#ifndef __FTP_H +#define __FTP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifndef CURL_DISABLE_FTP +CURLcode Curl_ftp(struct connectdata *conn, bool *done); +CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature); +CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done); +CURLcode Curl_ftp_disconnect(struct connectdata *conn); +CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); +CURLcode Curl_nbftpsendf(struct connectdata *, const char *fmt, ...); +CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, + int *ftpcode); +CURLcode Curl_ftp_nextconnect(struct connectdata *conn); +CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done); +int Curl_ftp_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); +CURLcode Curl_ftp_doing(struct connectdata *conn, + bool *dophase_done); +#endif /* CURL_DISABLE_FTP */ +#endif /* __FTP_H */ diff --git a/Utilities/cmcurl/lib/getenv.c b/Utilities/cmcurl/lib/getenv.c new file mode 100644 index 0000000..4f955f8 --- /dev/null +++ b/Utilities/cmcurl/lib/getenv.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include +#include + +#ifdef VMS +#include +#endif + +#include +#include "memory.h" + +#include "memdebug.h" + +static +char *GetEnv(const char *variable) +{ +#ifdef _WIN32_WCE + return NULL; +#else +#ifdef WIN32 + char env[MAX_PATH]; /* MAX_PATH is from windef.h */ + char *temp = getenv(variable); + env[0] = '\0'; + if (temp != NULL) + ExpandEnvironmentStrings(temp, env, sizeof(env)); +#else +#ifdef VMS + char *env = getenv(variable); + if (env && strcmp("HOME",variable) == 0) { + env = decc$translate_vms(env); + } +#else + /* no length control */ + char *env = getenv(variable); +#endif +#endif + return (env && env[0])?strdup(env):NULL; +#endif +} + +char *curl_getenv(const char *v) +{ + return GetEnv(v); +} diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c new file mode 100644 index 0000000..5cf3bca --- /dev/null +++ b/Utilities/cmcurl/lib/getinfo.c @@ -0,0 +1,234 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#include "urldata.h" +#include "getinfo.h" + +#include +#include +#include +#include +#include "memory.h" +#include "sslgen.h" + +/* Make this the last #include */ +#include "memdebug.h" + +/* + * This is supposed to be called in the beginning of a perform() session + * and should reset all session-info variables + */ +CURLcode Curl_initinfo(struct SessionHandle *data) +{ + struct Progress *pro = &data->progress; + struct PureInfo *info =&data->info; + + pro->t_nslookup = 0; + pro->t_connect = 0; + pro->t_pretransfer = 0; + pro->t_starttransfer = 0; + pro->timespent = 0; + pro->t_redirect = 0; + + info->httpcode = 0; + info->httpversion=0; + info->filetime=-1; /* -1 is an illegal time and thus means unknown */ + + if (info->contenttype) + free(info->contenttype); + info->contenttype = NULL; + + info->header_size = 0; + info->request_size = 0; + info->numconnects = 0; + return CURLE_OK; +} + +CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) +{ + va_list arg; + long *param_longp=NULL; + double *param_doublep=NULL; + char **param_charp=NULL; + struct curl_slist **param_slistp=NULL; + char buf; + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + va_start(arg, info); + + switch(info&CURLINFO_TYPEMASK) { + default: + return CURLE_BAD_FUNCTION_ARGUMENT; + case CURLINFO_STRING: + param_charp = va_arg(arg, char **); + if(NULL == param_charp) + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + case CURLINFO_LONG: + param_longp = va_arg(arg, long *); + if(NULL == param_longp) + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + case CURLINFO_DOUBLE: + param_doublep = va_arg(arg, double *); + if(NULL == param_doublep) + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + case CURLINFO_SLIST: + param_slistp = va_arg(arg, struct curl_slist **); + if(NULL == param_slistp) + return CURLE_BAD_FUNCTION_ARGUMENT; + break; + } + + switch(info) { + case CURLINFO_EFFECTIVE_URL: + *param_charp = data->change.url?data->change.url:(char *)""; + break; + case CURLINFO_RESPONSE_CODE: + *param_longp = data->info.httpcode; + break; + case CURLINFO_HTTP_CONNECTCODE: + *param_longp = data->info.httpproxycode; + break; + case CURLINFO_FILETIME: + *param_longp = data->info.filetime; + break; + case CURLINFO_HEADER_SIZE: + *param_longp = data->info.header_size; + break; + case CURLINFO_REQUEST_SIZE: + *param_longp = data->info.request_size; + break; + case CURLINFO_TOTAL_TIME: + *param_doublep = data->progress.timespent; + break; + case CURLINFO_NAMELOOKUP_TIME: + *param_doublep = data->progress.t_nslookup; + break; + case CURLINFO_CONNECT_TIME: + *param_doublep = data->progress.t_connect; + break; + case CURLINFO_PRETRANSFER_TIME: + *param_doublep = data->progress.t_pretransfer; + break; + case CURLINFO_STARTTRANSFER_TIME: + *param_doublep = data->progress.t_starttransfer; + break; + case CURLINFO_SIZE_UPLOAD: + *param_doublep = (double)data->progress.uploaded; + break; + case CURLINFO_SIZE_DOWNLOAD: + *param_doublep = (double)data->progress.downloaded; + break; + case CURLINFO_SPEED_DOWNLOAD: + *param_doublep = (double)data->progress.dlspeed; + break; + case CURLINFO_SPEED_UPLOAD: + *param_doublep = (double)data->progress.ulspeed; + break; + case CURLINFO_SSL_VERIFYRESULT: + *param_longp = data->set.ssl.certverifyresult; + break; + case CURLINFO_CONTENT_LENGTH_DOWNLOAD: + *param_doublep = (double)data->progress.size_dl; + break; + case CURLINFO_CONTENT_LENGTH_UPLOAD: + *param_doublep = (double)data->progress.size_ul; + break; + case CURLINFO_REDIRECT_TIME: + *param_doublep = data->progress.t_redirect; + break; + case CURLINFO_REDIRECT_COUNT: + *param_longp = data->set.followlocation; + break; + case CURLINFO_CONTENT_TYPE: + *param_charp = data->info.contenttype; + break; + case CURLINFO_PRIVATE: + *param_charp = data->set.private_data; + break; + case CURLINFO_HTTPAUTH_AVAIL: + *param_longp = data->info.httpauthavail; + break; + case CURLINFO_PROXYAUTH_AVAIL: + *param_longp = data->info.proxyauthavail; + break; + case CURLINFO_OS_ERRNO: + *param_longp = data->state.os_errno; + break; + case CURLINFO_NUM_CONNECTS: + *param_longp = data->info.numconnects; + break; + case CURLINFO_SSL_ENGINES: + *param_slistp = Curl_ssl_engines_list(data); + break; + case CURLINFO_COOKIELIST: + *param_slistp = Curl_cookie_list(data); + break; + case CURLINFO_FTP_ENTRY_PATH: + /* Return the entrypath string from the most recent connection. + This pointer was copied from the connectdata structure by FTP. + The actual string may be free()ed by subsequent libcurl calls so + it must be copied to a safer area before the next libcurl call. + Callers must never free it themselves. */ + *param_charp = data->state.most_recent_ftp_entrypath; + break; + case CURLINFO_LASTSOCKET: + if((data->state.lastconnect != -1) && + (data->state.connc->connects[data->state.lastconnect] != NULL)) { + struct connectdata *c = data->state.connc->connects + [data->state.lastconnect]; + *param_longp = c->sock[FIRSTSOCKET]; + /* we have a socket connected, let's determine if the server shut down */ + /* determine if ssl */ + if(c->ssl[FIRSTSOCKET].use) { + /* use the SSL context */ + if (!Curl_ssl_check_cxn(c)) + *param_longp = -1; /* FIN received */ + } +/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ +#ifdef MSG_PEEK + else { + /* use the socket */ + if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, + (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { + *param_longp = -1; /* FIN received */ + } + } +#endif + } + else + *param_longp = -1; + break; + default: + return CURLE_BAD_FUNCTION_ARGUMENT; + } + return CURLE_OK; +} diff --git a/Utilities/cmcurl/lib/getinfo.h b/Utilities/cmcurl/lib/getinfo.h new file mode 100644 index 0000000..2fe1b5c --- /dev/null +++ b/Utilities/cmcurl/lib/getinfo.h @@ -0,0 +1,28 @@ +#ifndef __GETINFO_H +#define __GETINFO_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...); +CURLcode Curl_initinfo(struct SessionHandle *data); + +#endif diff --git a/Utilities/cmcurl/lib/gtls.c b/Utilities/cmcurl/lib/gtls.c new file mode 100644 index 0000000..250ecad --- /dev/null +++ b/Utilities/cmcurl/lib/gtls.c @@ -0,0 +1,640 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code + * but sslgen.c should ever call or use these functions. + * + * Note: don't use the GnuTLS' *_t variable type names in this source code, + * since they were not present in 1.0.X. + */ + +#include "setup.h" +#ifdef USE_GNUTLS +#include +#include + +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "gtls.h" +#include "sslgen.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#define _MPRINTF_REPLACE /* use our functions only */ +#include +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* Enable GnuTLS debugging by defining GTLSDEBUG */ +/*#define GTLSDEBUG */ + +#ifdef GTLSDEBUG +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} +#endif + +/* + * Custom push and pull callback functions used by GNU TLS to read and write + * to the socket. These functions are simple wrappers to send() and recv() + * (although here using the sread/swrite macros as defined by setup_once.h). + * We use custom functions rather than the GNU TLS defaults because it allows + * us to get specific about the fourth "flags" argument, and to use arbitrary + * private data with gnutls_transport_set_ptr if we wish. + */ +static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) +{ + return swrite(s, buf, len); +} + +static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) +{ + return sread(s, buf, len); +} + +/* Global GnuTLS init, called from Curl_ssl_init() */ +int Curl_gtls_init(void) +{ + gnutls_global_init(); +#ifdef GTLSDEBUG + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(2); +#endif + return 1; +} + +int Curl_gtls_cleanup(void) +{ + gnutls_global_deinit(); + return 1; +} + +static void showtime(struct SessionHandle *data, + const char *text, + time_t stamp) +{ + struct tm *tm; +#ifdef HAVE_GMTIME_R + struct tm buffer; + tm = (struct tm *)gmtime_r(&stamp, &buffer); +#else + tm = gmtime(&stamp); +#endif + snprintf(data->state.buffer, + BUFSIZE, + "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n", + text, + 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); + infof(data, "%s", data->state.buffer); +} + +/* this function does a BLOCKING SSL/TLS (re-)handshake */ +static CURLcode handshake(struct connectdata *conn, + gnutls_session session, + int sockindex, + bool duringconnect) +{ + struct SessionHandle *data = conn->data; + int rc; + + do { + rc = gnutls_handshake(session); + + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + long timeout_ms = DEFAULT_CONNECT_TIMEOUT; + long has_passed; + + if(duringconnect && data->set.connecttimeout) + timeout_ms = data->set.connecttimeout*1000; + + if(data->set.timeout) { + /* get the strictest timeout of the ones converted to milliseconds */ + if((data->set.timeout*1000) < timeout_ms) + timeout_ms = data->set.timeout*1000; + } + + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + + /* subtract the passed time */ + timeout_ms -= has_passed; + + if(timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEOUTED; + } + + rc = Curl_select(conn->sock[sockindex], + conn->sock[sockindex], (int)timeout_ms); + if(rc > 0) + /* reabable or writable, go loop*/ + continue; + else if(0 == rc) { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + return CURLE_SSL_CONNECT_ERROR; + } + } + else + break; + } while(1); + + if (rc < 0) { + failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + + return CURLE_OK; +} + +static gnutls_x509_crt_fmt do_file_type(const char *type) +{ + if(!type || !type[0]) + return GNUTLS_X509_FMT_PEM; + if(curl_strequal(type, "PEM")) + return GNUTLS_X509_FMT_PEM; + if(curl_strequal(type, "DER")) + return GNUTLS_X509_FMT_DER; + return -1; +} + + +/* + * This function is called after the TCP connect has completed. Setup the TLS + * layer and do all necessary magic. + */ +CURLcode +Curl_gtls_connect(struct connectdata *conn, + int sockindex) + +{ + const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; + struct SessionHandle *data = conn->data; + gnutls_session session; + int rc; + unsigned int cert_list_size; + const gnutls_datum *chainp; + unsigned int verify_status; + gnutls_x509_crt x509_cert; + char certbuf[256]; /* big enough? */ + size_t size; + unsigned int algo; + unsigned int bits; + time_t clock; + const char *ptr; + void *ssl_sessionid; + size_t ssl_idsize; + + /* GnuTLS only supports TLSv1 (and SSLv3?) */ + if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + failf(data, "GnuTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* allocate a cred struct */ + rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); + if(rc < 0) { + failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + + if(data->set.ssl.CAfile) { + /* set the trusted CA cert bundle file */ + gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + data->set.ssl.CAfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)\n", + data->set.ssl.CAfile, gnutls_strerror(rc)); + if (data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "found %d certificates in %s\n", + rc, data->set.ssl.CAfile); + } + + /* Initialize TLS session as a client */ + rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); + if(rc) { + failf(data, "gnutls_init() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* convenient assign */ + session = conn->ssl[sockindex].session; + + /* Use default priorities */ + rc = gnutls_set_default_priority(session); + if(rc < 0) + return CURLE_SSL_CONNECT_ERROR; + + /* Sets the priority on the certificate types supported by gnutls. Priority + is higher for types specified before others. After specifying the types + you want, you must append a 0. */ + rc = gnutls_certificate_type_set_priority(session, cert_type_priority); + if(rc < 0) + return CURLE_SSL_CONNECT_ERROR; + + if(data->set.cert) { + if( gnutls_certificate_set_x509_key_file( + conn->ssl[sockindex].cred, data->set.cert, + data->set.key != 0 ? data->set.key : data->set.cert, + do_file_type(data->set.cert_type) ) ) { + failf(data, "error reading X.509 key or certificate file"); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* put the credentials to the current session */ + rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, + conn->ssl[sockindex].cred); + + /* set the connection handle (file descriptor for the socket) */ + gnutls_transport_set_ptr(session, + (gnutls_transport_ptr)conn->sock[sockindex]); + + /* register callback functions to send and receive data. */ + gnutls_transport_set_push_function(session, Curl_gtls_push); + gnutls_transport_set_pull_function(session, Curl_gtls_pull); + + /* lowat must be set to zero when using custom push and pull functions. */ + gnutls_transport_set_lowat(session, 0); + + /* This might be a reconnect, so we check for a session ID in the cache + to speed up things */ + + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + + rc = handshake(conn, session, sockindex, TRUE); + if(rc) + /* handshake() sets its own error message with failf() */ + return rc; + + /* This function will return the peer's raw certificate (chain) as sent by + the peer. These certificates are in raw format (DER encoded for + X.509). In case of a X.509 then a certificate list may be present. The + first certificate in the list is the peer's certificate, following the + issuer's certificate, then the issuer's issuer etc. */ + + chainp = gnutls_certificate_get_peers(session, &cert_list_size); + if(!chainp) { + if(data->set.ssl.verifyhost) { + failf(data, "failed to get server cert"); + return CURLE_SSL_PEER_CERTIFICATE; + } + infof(data, "\t common name: WARNING couldn't obtain\n"); + } + + /* This function will try to verify the peer's certificate and return its + status (trusted, invalid etc.). The value of status should be one or more + of the gnutls_certificate_status_t enumerated elements bitwise or'd. To + avoid denial of service attacks some default upper limits regarding the + certificate key size and chain size are set. To override them use + gnutls_certificate_set_verify_limits(). */ + + rc = gnutls_certificate_verify_peers2(session, &verify_status); + if (rc < 0) { + failf(data, "server cert verify failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* verify_status is a bitmask of gnutls_certificate_status bits */ + if(verify_status & GNUTLS_CERT_INVALID) { + if (data->set.ssl.verifypeer) { + failf(data, "server certificate verification failed. CAfile: %s", + data->set.ssl.CAfile?data->set.ssl.CAfile:"none"); + return CURLE_SSL_CACERT; + } + else + infof(data, "\t server certificate verification FAILED\n"); + } + else + infof(data, "\t server certificate verification OK\n"); + + /* initialize an X.509 certificate structure. */ + gnutls_x509_crt_init(&x509_cert); + + /* convert the given DER or PEM encoded Certificate to the native + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + + size=sizeof(certbuf); + rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, + 0, /* the first and only one */ + FALSE, + certbuf, + &size); + if(rc) { + infof(data, "error fetching CN from cert:%s\n", + gnutls_strerror(rc)); + } + + /* This function will check if the given certificate's subject matches the + given hostname. This is a basic implementation of the matching described + in RFC2818 (HTTPS), which takes into account wildcards, and the subject + alternative name PKIX extension. Returns non zero on success, and zero on + failure. */ + rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); + + if(!rc) { + if (data->set.ssl.verifyhost > 1) { + failf(data, "SSL: certificate subject name (%s) does not match " + "target host name '%s'", certbuf, conn->host.dispname); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "\t common name: %s (does not match '%s')\n", + certbuf, conn->host.dispname); + } + else + infof(data, "\t common name: %s (matched)\n", certbuf); + + /* Show: + + - ciphers used + - subject + - start date + - expire date + - common name + - issuer + + */ + + /* public key algorithm's parameters */ + algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); + infof(data, "\t certificate public key: %s\n", + gnutls_pk_algorithm_get_name(algo)); + + /* version of the X.509 certificate. */ + infof(data, "\t certificate version: #%d\n", + gnutls_x509_crt_get_version(x509_cert)); + + + size = sizeof(certbuf); + gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); + infof(data, "\t subject: %s\n", certbuf); + + clock = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", clock); + + clock = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", clock); + + size = sizeof(certbuf); + gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); + infof(data, "\t issuer: %s\n", certbuf); + + gnutls_x509_crt_deinit(x509_cert); + + /* compression algorithm (if any) */ + ptr = gnutls_compression_get_name(gnutls_compression_get(session)); + /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ + infof(data, "\t compression: %s\n", ptr); + + /* the name of the cipher used. ie 3DES. */ + ptr = gnutls_cipher_get_name(gnutls_cipher_get(session)); + infof(data, "\t cipher: %s\n", ptr); + + /* the MAC algorithms name. ie SHA1 */ + ptr = gnutls_mac_get_name(gnutls_mac_get(session)); + infof(data, "\t MAC: %s\n", ptr); + + if(!ssl_sessionid) { + /* this session was not previously in the cache, add it now */ + + /* get the session ID data size */ + gnutls_session_get_data(session, NULL, &ssl_idsize); + ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */ + + if(ssl_sessionid) { + /* extract session ID to the allocated buffer */ + gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize); + + /* store this session id */ + return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize); + } + } + + return CURLE_OK; +} + + +/* return number of sent (non-SSL) bytes */ +ssize_t Curl_gtls_send(struct connectdata *conn, + int sockindex, + void *mem, + size_t len) +{ + ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); + + if(rc < 0 ) { + if(rc == GNUTLS_E_AGAIN) + return 0; /* EWOULDBLOCK equivalent */ + rc = -1; /* generic error code for send failure */ + } + + return rc; +} + +void Curl_gtls_close_all(struct SessionHandle *data) +{ + /* FIX: make the OpenSSL code more generic and use parts of it here */ + (void)data; +} + +static void close_one(struct connectdata *conn, + int index) +{ + if(conn->ssl[index].session) { + gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR); + gnutls_deinit(conn->ssl[index].session); + } + gnutls_certificate_free_credentials(conn->ssl[index].cred); +} + +void Curl_gtls_close(struct connectdata *conn) +{ + if(conn->ssl[0].use) + close_one(conn, 0); + if(conn->ssl[1].use) + close_one(conn, 1); +} + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) +{ + int result; + int retval = 0; + struct SessionHandle *data = conn->data; + int done = 0; + ssize_t nread; + char buf[120]; + + /* 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(conn->ssl[sockindex].session) { + while(!done) { + int what = Curl_select(conn->sock[sockindex], + CURL_SOCKET_BAD, 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(conn->ssl[sockindex].session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = 1; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); + break; + default: + retval = -1; + done = 1; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = 1; + break; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + retval = -1; + done = 1; + } + } + gnutls_deinit(conn->ssl[sockindex].session); + } + gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); + + conn->ssl[sockindex].session = NULL; + conn->ssl[sockindex].use = FALSE; + + return retval; +} + +/* + * If the read would block we return -1 and set 'wouldblock' to TRUE. + * Otherwise we return the amount of data read. Other errors should return -1 + * and set 'wouldblock' to FALSE. + */ +ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + bool *wouldblock) +{ + ssize_t ret; + + ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); + if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { + *wouldblock = TRUE; + return -1; + } + + if(ret == GNUTLS_E_REHANDSHAKE) { + /* BLOCKING call, this is bad but a work-around for now. Fixing this "the + proper way" takes a whole lot of work. */ + CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE); + if(rc) + /* handshake() writes error message on its own */ + return rc; + *wouldblock = TRUE; /* then return as if this was a wouldblock */ + return -1; + } + + *wouldblock = FALSE; + if (!ret) { + failf(conn->data, "Peer closed the TLS connection"); + return -1; + } + + if (ret < 0) { + failf(conn->data, "GnuTLS recv error (%d): %s", + (int)ret, gnutls_strerror(ret)); + return -1; + } + + return ret; +} + +void Curl_gtls_session_free(void *ptr) +{ + free(ptr); +} + +size_t Curl_gtls_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, " GnuTLS/%s", gnutls_check_version(NULL)); +} + +#endif /* USE_GNUTLS */ diff --git a/Utilities/cmcurl/lib/gtls.h b/Utilities/cmcurl/lib/gtls.h new file mode 100644 index 0000000..bff3f86 --- /dev/null +++ b/Utilities/cmcurl/lib/gtls.h @@ -0,0 +1,46 @@ +#ifndef __GTLS_H +#define __GTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +int Curl_gtls_init(void); +int Curl_gtls_cleanup(void); +CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); + +/* tell GnuTLS to close down all open information regarding connections (and + thus session ID caching etc) */ +void Curl_gtls_close_all(struct SessionHandle *data); +void Curl_gtls_close(struct connectdata *conn); /* close a SSL connection */ + +/* return number of sent (non-SSL) bytes */ +ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex, + void *mem, size_t len); +ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + bool *wouldblock); +void Curl_gtls_session_free(void *ptr); +size_t Curl_gtls_version(char *buffer, size_t size); +int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); + +#endif diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c new file mode 100644 index 0000000..e004627 --- /dev/null +++ b/Utilities/cmcurl/lib/hash.c @@ -0,0 +1,315 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#include "hash.h" +#include "llist.h" +#include "memory.h" + +/* this must be the last include file */ +#include "memdebug.h" + +static unsigned long +hash_str(const char *key, size_t key_length) +{ + char *end = (char *) key + key_length; + unsigned long h = 5381; + + while (key < end) { + h += h << 5; + h ^= (unsigned long) *key++; + } + + return h; +} + +static void +hash_element_dtor(void *user, void *element) +{ + struct curl_hash *h = (struct curl_hash *) user; + struct curl_hash_element *e = (struct curl_hash_element *) element; + + if (e->key) + free(e->key); + + h->dtor(e->ptr); + + free(e); +} + +/* return 1 on error, 0 is fine */ +int +Curl_hash_init(struct curl_hash *h, int slots, curl_hash_dtor dtor) +{ + int i; + + h->dtor = dtor; + h->size = 0; + h->slots = slots; + + h->table = (struct curl_llist **) malloc(slots * sizeof(struct curl_llist *)); + if(h->table) { + for (i = 0; i < slots; ++i) { + h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); + if(!h->table[i]) { + while(i--) + Curl_llist_destroy(h->table[i], NULL); + free(h->table); + return 1; /* failure */ + } + } + return 0; /* fine */ + } + else + return 1; /* failure */ +} + +struct curl_hash * +Curl_hash_alloc(int slots, curl_hash_dtor dtor) +{ + struct curl_hash *h; + + h = (struct curl_hash *) malloc(sizeof(struct curl_hash)); + if (h) { + if(Curl_hash_init(h, slots, dtor)) { + /* failure */ + free(h); + h = NULL; + } + } + + return h; +} + +static int +hash_key_compare(char *key1, size_t key1_len, char *key2, size_t key2_len) +{ + if (key1_len == key2_len && + *key1 == *key2 && + memcmp(key1, key2, key1_len) == 0) { + return 1; + } + + return 0; +} + +static struct curl_hash_element * +mk_hash_element(char *key, size_t key_len, const void *p) +{ + struct curl_hash_element *he = + (struct curl_hash_element *) malloc(sizeof(struct curl_hash_element)); + + if(he) { + char *dup = malloc(key_len); + if(dup) { + /* copy the key */ + memcpy(dup, key, key_len); + + he->key = dup; + he->key_len = key_len; + he->ptr = (void *) p; + } + else { + /* failed to duplicate the key, free memory and fail */ + free(he); + he = NULL; + } + } + return he; +} + +#define find_slot(__h, __k, __k_len) (hash_str(__k, __k_len) % (__h)->slots) + +#define FETCH_LIST(x,y,z) x->table[find_slot(x, y, z)] + +/* Return the data in the hash. If there already was a match in the hash, + that data is returned. */ +void * +Curl_hash_add(struct curl_hash *h, char *key, size_t key_len, void *p) +{ + struct curl_hash_element *he; + struct curl_llist_element *le; + struct curl_llist *l = FETCH_LIST(h, key, key_len); + + for (le = l->head; le; le = le->next) { + he = (struct curl_hash_element *) le->ptr; + if (hash_key_compare(he->key, he->key_len, key, key_len)) { + h->dtor(p); /* remove the NEW entry */ + return he->ptr; /* return the EXISTING entry */ + } + } + + he = mk_hash_element(key, key_len, p); + if (he) { + if(Curl_llist_insert_next(l, l->tail, he)) { + ++h->size; + return p; /* return the new entry */ + } + /* + * Couldn't insert it, destroy the 'he' element and the key again. We + * don't call hash_element_dtor() since that would also call the + * "destructor" for the actual data 'p'. When we fail, we shall not touch + * that data. + */ + free(he->key); + free(he); + } + + return NULL; /* failure */ +} + +/* remove the identified hash entry, returns non-zero on failure */ +int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len) +{ + struct curl_llist_element *le; + struct curl_hash_element *he; + struct curl_llist *l = FETCH_LIST(h, key, key_len); + + for (le = l->head; le; le = le->next) { + he = le->ptr; + if (hash_key_compare(he->key, he->key_len, key, key_len)) { + Curl_llist_remove(l, le, (void *) h); + return 0; + } + } + return 1; +} + +void * +Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len) +{ + struct curl_llist_element *le; + struct curl_hash_element *he; + struct curl_llist *l = FETCH_LIST(h, key, key_len); + + for (le = l->head; le; le = le->next) { + he = le->ptr; + if (hash_key_compare(he->key, he->key_len, key, key_len)) { + return he->ptr; + } + } + + return NULL; +} + +#if defined(CURLDEBUG) && defined(AGGRESIVE_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 + +void +Curl_hash_clean(struct curl_hash *h) +{ + int i; + + for (i = 0; i < h->slots; ++i) { + Curl_llist_destroy(h->table[i], (void *) h); + } + + free(h->table); +} + +void +Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, + int (*comp)(void *, void *)) +{ + struct curl_llist_element *le; + struct curl_llist_element *lnext; + struct curl_llist *list; + int i; + + for (i = 0; i < h->slots; ++i) { + list = h->table[i]; + le = list->head; /* get first list entry */ + while(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(user, he->ptr)) { + Curl_llist_remove(list, le, (void *) h); + --h->size; /* one less entry in the hash now */ + } + le = lnext; + } + } +} + +void +Curl_hash_destroy(struct curl_hash *h) +{ + if (!h) + return; + + Curl_hash_clean(h); + free(h); +} + +#if 0 /* useful function for debugging hashes and their contents */ +void Curl_hash_print(struct curl_hash *h, + void (*func)(void *)) +{ + int i; + struct curl_llist_element *le; + struct curl_llist *list; + struct curl_hash_element *he; + if (!h) + return; + + fprintf(stderr, "=Hash dump=\n"); + + for (i = 0; i < h->slots; i++) { + list = h->table[i]; + le = list->head; /* get first list entry */ + if(le) { + fprintf(stderr, "index %d:", i); + while(le) { + he = le->ptr; + if(func) + func(he->ptr); + else + fprintf(stderr, " [%p]", he->ptr); + le = le->next; + } + fprintf(stderr, "\n"); + } + } +} +#endif diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h new file mode 100644 index 0000000..ceebb52 --- /dev/null +++ b/Utilities/cmcurl/lib/hash.h @@ -0,0 +1,61 @@ +#ifndef __HASH_H +#define __HASH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#include "llist.h" + +typedef void (*curl_hash_dtor)(void *); + +struct curl_hash { + struct curl_llist **table; + curl_hash_dtor dtor; + int slots; + size_t size; +}; + +struct curl_hash_element { + void *ptr; + char *key; + size_t key_len; +}; + + +int Curl_hash_init(struct curl_hash *, int, curl_hash_dtor); +struct curl_hash *Curl_hash_alloc(int, curl_hash_dtor); +void *Curl_hash_add(struct curl_hash *, char *, size_t, void *); +int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len); +void *Curl_hash_pick(struct curl_hash *, char *, size_t); +void Curl_hash_apply(struct curl_hash *h, void *user, + void (*cb)(void *user, void *ptr)); +int 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 *)); +void Curl_hash_destroy(struct curl_hash *h); + +#endif diff --git a/Utilities/cmcurl/lib/hostares.c b/Utilities/cmcurl/lib/hostares.c new file mode 100644 index 0000000..1db0f43 --- /dev/null +++ b/Utilities/cmcurl/lib/hostares.c @@ -0,0 +1,307 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "multiif.h" +#include "connect.h" /* for the Curl_sockerrno() proto */ + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#include "memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/*********************************************************************** + * Only for ares-enabled builds + **********************************************************************/ + +#ifdef CURLRES_ARES + +/* + * Curl_resolv_fdset() is called when someone from the outside world (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. + * + * Returns: CURLE_OK always! + */ + +int Curl_resolv_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) + +{ + struct timeval maxtime; + struct timeval timeout; + int max = ares_getsock(conn->data->state.areschannel, + (int *)socks, numsocks); + + + maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; + maxtime.tv_usec = 0; + + ares_timeout(conn->data->state.areschannel, &maxtime, &timeout); + + Curl_expire(conn->data, + (timeout.tv_sec * 1000) + (timeout.tv_usec/1000) ); + + return max; +} + +/* + * Curl_is_resolved() is called repeatedly to check if a previous name resolve + * request has completed. It should also make sure to time-out if the + * operation seems to take too long. + * + * Returns normal CURLcode errors. + */ +CURLcode Curl_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **dns) +{ + fd_set read_fds, write_fds; + struct timeval tv={0,0}; + struct SessionHandle *data = conn->data; + int nfds; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + + nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); + + (void)select(nfds, &read_fds, &write_fds, NULL, + (struct timeval *)&tv); + + /* Call ares_process() unconditonally here, even if we simply timed out + above, as otherwise the ares name resolve won't timeout! */ + ares_process(data->state.areschannel, &read_fds, &write_fds); + + *dns = NULL; + + if(conn->async.done) { + /* we're done, kill the ares handle */ + if(!conn->async.dns) { + failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, + ares_strerror(conn->async.status)); + return CURLE_COULDNT_RESOLVE_HOST; + } + *dns = conn->async.dns; + } + + return CURLE_OK; +} + +/* + * Curl_wait_for_resolv() waits for a resolve to finish. This function should + * be avoided since using this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and + * CURLE_OPERATION_TIMEDOUT if a time-out occurred. + */ +CURLcode Curl_wait_for_resolv(struct connectdata *conn, + struct Curl_dns_entry **entry) +{ + CURLcode rc=CURLE_OK; + struct SessionHandle *data = conn->data; + long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */ + + /* now, see if there's a connect timeout or a regular timeout to + use instead of the default one */ + if(conn->data->set.connecttimeout) + timeout = conn->data->set.connecttimeout; + else if(conn->data->set.timeout) + timeout = conn->data->set.timeout; + + /* We convert the number of seconds into number of milliseconds here: */ + if(timeout < 2147483) + /* maximum amount of seconds that can be multiplied with 1000 and + still fit within 31 bits */ + timeout *= 1000; + else + timeout = 0x7fffffff; /* ridiculous amount of time anyway */ + + /* Wait for the name resolve query to complete. */ + while (1) { + int nfds=0; + fd_set read_fds, write_fds; + struct timeval *tvp, tv, store; + int count; + struct timeval now = Curl_tvnow(); + long timediff; + + store.tv_sec = (int)timeout/1000; + store.tv_usec = (timeout%1000)*1000; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); + if (nfds == 0) + /* no file descriptors means we're done waiting */ + break; + tvp = ares_timeout(data->state.areschannel, &store, &tv); + count = select(nfds, &read_fds, &write_fds, NULL, tvp); + if (count < 0 && Curl_sockerrno() != EINVAL) + break; + + ares_process(data->state.areschannel, &read_fds, &write_fds); + + timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */ + timeout -= timediff?timediff:1; /* always deduct at least 1 */ + if (timeout < 0) { + /* our timeout, so we cancel the ares operation */ + ares_cancel(data->state.areschannel); + break; + } + } + + /* Operation complete, if the lookup was successful we now have the entry + in the cache. */ + + if(entry) + *entry = conn->async.dns; + + if(!conn->async.dns) { + /* a name was not resolved */ + if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { + failf(data, "Resolving host timed out: %s", conn->host.dispname); + rc = CURLE_OPERATION_TIMEDOUT; + } + else if(conn->async.done) { + failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, + ares_strerror(conn->async.status)); + rc = CURLE_COULDNT_RESOLVE_HOST; + } + else + rc = CURLE_OPERATION_TIMEDOUT; + + /* close the connection, since we can't return failure here without + cleaning up this connection properly */ + conn->bits.close = TRUE; + } + + return rc; +} + +/* + * Curl_getaddrinfo() - when using ares + * + * Returns name information about the given hostname and port number. If + * successful, the 'hostent' is returned and the forth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + char *bufp; + struct SessionHandle *data = conn->data; + in_addr_t in = inet_addr(hostname); + + *waitp = FALSE; + + if (in != CURL_INADDR_NONE) { + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(in, hostname, port); + } + + bufp = strdup(hostname); + + if(bufp) { + Curl_safefree(conn->async.hostname); + conn->async.hostname = bufp; + conn->async.port = port; + conn->async.done = FALSE; /* not done */ + conn->async.status = 0; /* clear */ + conn->async.dns = NULL; /* clear */ + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname(data->state.areschannel, hostname, PF_INET, + (ares_host_callback)Curl_addrinfo4_callback, conn); + + *waitp = TRUE; /* please wait for the response */ + } + return NULL; /* no struct yet */ +} +#endif /* CURLRES_ARES */ diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c new file mode 100644 index 0000000..3df1479 --- /dev/null +++ b/Utilities/cmcurl/lib/hostasyn.c @@ -0,0 +1,174 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/*********************************************************************** + * Only for builds using asynchronous name resolves + **********************************************************************/ +#ifdef CURLRES_ASYNCH +/* + * addrinfo_callback() gets called by ares, gethostbyname_thread() or + * getaddrinfo_thread() when we got the name resolved (or not!). + * + * If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the + * address field since it might be freed when this function returns. This + * operation stores the resolved data in the DNS cache. + * + * NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same + * pointer it is given as argument! + * + * The storage operation locks and unlocks the DNS cache. + */ +static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */ + int status, + void *addr) +{ + struct connectdata *conn = (struct connectdata *)arg; + struct Curl_dns_entry *dns = NULL; + CURLcode rc = CURLE_OK; + + conn->async.status = status; + + if(CURL_ASYNC_SUCCESS == status) { + + /* + * IPv4/ares: Curl_addrinfo_copy() copies the address and returns an + * allocated version. + * + * IPv6: Curl_addrinfo_copy() returns the input pointer! + */ + Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port); + if(ai) { + struct SessionHandle *data = conn->data; + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns = Curl_cache_addr(data, ai, + conn->async.hostname, + conn->async.port); + if(!dns) { + /* failed to store, cleanup and return error */ + Curl_freeaddrinfo(ai); + rc = CURLE_OUT_OF_MEMORY; + } + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + } + else + rc = CURLE_OUT_OF_MEMORY; + } + + conn->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 */ + conn->async.done = TRUE; + + /* ipv4: The input hostent struct will be freed by ares when we return from + this function */ + return rc; +} + +CURLcode Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */ + int status, + struct hostent *hostent) +{ + return addrinfo_callback(arg, status, hostent); +} + +#ifdef CURLRES_IPV6 +CURLcode Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */ + int status, + struct addrinfo *ai) +{ + /* NOTE: for CURLRES_ARES, the 'ai' argument is really a + * 'struct hostent' pointer. + */ + return addrinfo_callback(arg, status, ai); +} +#endif + +#endif /* CURLRES_ASYNC */ diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c new file mode 100644 index 0000000..83f1564 --- /dev/null +++ b/Utilities/cmcurl/lib/hostip.c @@ -0,0 +1,636 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "inet_ntop.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * hostip.c explained + * ================== + * + * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c + * 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 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 + * asynchronous name resolves. This can be Windows or *nix. + * + * CURLRES_THREADED - is defined if libcurl is built to run under (native) + * Windows, and then the name resolve will be done in a new thread, and the + * supported API will be the same as for ares-builds. + * + * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If + * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is + * defined. + * + * The host*.c sources files are split up like this: + * + * hostip.c - method-independent resolver functions and utility functions + * hostasyn.c - functions for asynchronous name resolves + * hostsyn.c - functions for synchronous name resolves + * hostares.c - functions for ares-using name resolves + * hostthre.c - functions for threaded name resolves + * hostip4.c - ipv4-specific functions + * hostip6.c - ipv6-specific functions + * + * The hostip.h is the united header file for all this. It defines the + * CURLRES_* defines based on the config*.h and setup.h defines. + */ + +/* These two symbols are for the global DNS cache */ +static struct curl_hash hostname_cache; +static int host_cache_initialized; + +static void freednsentry(void *freethis); + +/* + * Curl_global_host_cache_init() initializes and sets up a global DNS cache. + * Global DNS cache is general badness. Do not use. This will be removed in + * a future version. Use the share interface instead! + */ +void Curl_global_host_cache_init(void) +{ + if (!host_cache_initialized) { + Curl_hash_init(&hostname_cache, 7, freednsentry); + host_cache_initialized = 1; + } +} + +/* + * Return a pointer to the global cache + */ +struct curl_hash *Curl_global_host_cache_get(void) +{ + return &hostname_cache; +} + +/* + * Destroy and cleanup the global DNS cache + */ +void Curl_global_host_cache_dtor(void) +{ + if (host_cache_initialized) { + Curl_hash_clean(&hostname_cache); + host_cache_initialized = 0; + } +} + +/* + * Return # of adresses in a Curl_addrinfo struct + */ +int Curl_num_addresses(const Curl_addrinfo *addr) +{ + int i; + for (i = 0; addr; addr = addr->ai_next, i++) + ; /* empty loop */ + return i; +} + +/* + * Curl_printable_address() returns a printable version of the 1st address + * given in the 'ip' argument. The result will be stored in the buf that is + * bufsize bytes big. + * + * If the conversion fails, it returns NULL. + */ +const char *Curl_printable_address(const Curl_addrinfo *ip, + char *buf, size_t bufsize) +{ + const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr; + int af = ip->ai_family; +#ifdef CURLRES_IPV6 + const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr; +#else + const void *ip6 = NULL; +#endif + + return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize); +} + +/* + * Return a hostcache id string for the providing host + port, to be used by + * the DNS caching. + */ +static char * +create_hostcache_id(const char *server, int port) +{ + /* create and return the new allocated entry */ + return aprintf("%s:%d", server, port); +} + +struct hostcache_prune_data { + int cache_timeout; + time_t now; +}; + +/* + * This function is set as a callback to be called for every entry in the DNS + * cache when we want to prune old unused entries. + * + * Returning non-zero means remove the entry, return 0 to keep it in the + * cache. + */ +static int +hostcache_timestamp_remove(void *datap, void *hc) +{ + struct hostcache_prune_data *data = + (struct hostcache_prune_data *) datap; + struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; + + if ((data->now - c->timestamp < data->cache_timeout) || + c->inuse) { + /* please don't remove */ + return 0; + } + + /* fine, remove */ + return 1; +} + +/* + * Prune the DNS cache. This assumes that a lock has already been taken. + */ +static void +hostcache_prune(struct curl_hash *hostcache, int cache_timeout, time_t now) +{ + struct hostcache_prune_data user; + + user.cache_timeout = cache_timeout; + user.now = now; + + Curl_hash_clean_with_criterium(hostcache, + (void *) &user, + hostcache_timestamp_remove); +} + +/* + * Library-wide function for pruning the DNS cache. This function takes and + * returns the appropriate locks. + */ +void Curl_hostcache_prune(struct SessionHandle *data) +{ + time_t now; + + if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache) + /* cache forever means never prune, and NULL hostcache means + we can't do it */ + return; + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + time(&now); + + /* Remove outdated and unused entries from the hostcache */ + hostcache_prune(data->dns.hostcache, + data->set.dns_cache_timeout, + now); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); +} + +static int +remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns) +{ + struct hostcache_prune_data user; + + if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache) + /* cache forever means never prune, and NULL hostcache means + we can't do it */ + return 0; + + time(&user.now); + user.cache_timeout = data->set.dns_cache_timeout; + + if ( !hostcache_timestamp_remove(&user,dns) ) + return 0; + + /* ok, we do need to clear the cache. although we need to remove just a + single entry we clean the entire hash, as no explicit delete function + is provided */ + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + Curl_hash_clean_with_criterium(data->dns.hostcache, + (void *) &user, + hostcache_timestamp_remove); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + return 1; +} + + +#ifdef HAVE_SIGSETJMP +/* Beware this is a global and unique instance. This is used to store the + return address that we can jump back to from inside a signal handler. This + is not thread-safe stuff. */ +sigjmp_buf curl_jmpenv; +#endif + + +/* + * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. + * + * When calling Curl_resolv() has resulted in a response with a returned + * address, we call this function to store the information in the dns + * cache etc + * + * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. + */ +struct Curl_dns_entry * +Curl_cache_addr(struct SessionHandle *data, + Curl_addrinfo *addr, + const char *hostname, + int port) +{ + char *entry_id; + size_t entry_len; + struct Curl_dns_entry *dns; + struct Curl_dns_entry *dns2; + time_t now; + + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if (!entry_id) + return NULL; + entry_len = strlen(entry_id); + + /* Create a new cache entry */ + dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1); + if (!dns) { + free(entry_id); + return NULL; + } + + dns->inuse = 0; /* init to not used */ + dns->addr = addr; /* this is the address(es) */ + + /* Store the resolved data in our DNS cache. This function may return a + pointer to an existing struct already present in the hash, and it may + return the same argument we pass in. Make no assumptions. */ + dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1, + (void *)dns); + if(!dns2) { + /* Major badness, run away. */ + free(dns); + free(entry_id); + return NULL; + } + time(&now); + dns = dns2; + + dns->timestamp = now; /* used now */ + dns->inuse++; /* mark entry as in-use */ + + /* free the allocated entry_id again */ + free(entry_id); + + return dns; +} + +/* + * 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'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_unlock() later (when you're + * done using this struct) to decrease the counter again. + * + * Return codes: + * + * CURLRESOLV_ERROR (-1) = error, no pointer + * CURLRESOLV_RESOLVED (0) = OK, pointer provided + * CURLRESOLV_PENDING (1) = waiting for response, no pointer + */ + +int Curl_resolv(struct connectdata *conn, + const char *hostname, + int port, + struct Curl_dns_entry **entry) +{ + char *entry_id = NULL; + struct Curl_dns_entry *dns = NULL; + size_t entry_len; + int wait; + struct SessionHandle *data = conn->data; + CURLcode result; + int rc; + *entry = NULL; + +#ifdef HAVE_SIGSETJMP + /* this allows us to time-out from the name resolver, as the timeout + will generate a signal and we will siglongjmp() from that here */ + if(!data->set.no_signal) { + if (sigsetjmp(curl_jmpenv, 1)) { + /* this is coming from a siglongjmp() */ + failf(data, "name lookup timed out"); + return CURLRESOLV_ERROR; + } + } +#endif + + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if (!entry_id) + return CURLRESOLV_ERROR; + + entry_len = strlen(entry_id); + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* See if its already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + /* free the allocated entry_id again */ + free(entry_id); + + /* See whether the returned entry is stale. Deliberately done after the + locked block */ + if ( remove_entry_if_stale(data,dns) ) + dns = NULL; /* the memory deallocation is being handled by the hash */ + + rc = CURLRESOLV_ERROR; /* default to failure */ + + if (!dns) { + /* The entry was not in the cache. Resolve it to IP address */ + + Curl_addrinfo *addr; + + /* Check what IP specifics the app has requested and if we can provide it. + * If not, bail out. */ + if(!Curl_ipvalid(data)) + return CURLRESOLV_ERROR; + + /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero + value indicating that we need to wait for the response to the resolve + call */ + addr = Curl_getaddrinfo(conn, hostname, port, &wait); + + if (!addr) { + if(wait) { + /* the response to our resolve call will come asynchronously at + a later time, good or bad */ + /* First, check that we haven't received the info by now */ + result = Curl_is_resolved(conn, &dns); + if(result) /* error detected */ + return CURLRESOLV_ERROR; + if(dns) + rc = CURLRESOLV_RESOLVED; /* pointer provided */ + else + rc = CURLRESOLV_PENDING; /* no info yet */ + } + } + else { + if(data->share) + 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, port); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) + /* returned failure, bail out nicely */ + Curl_freeaddrinfo(addr); + else + rc = CURLRESOLV_RESOLVED; + } + } + else { + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + dns->inuse++; /* we use it! */ + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + rc = CURLRESOLV_RESOLVED; + } + + *entry = dns; + + return rc; +} + +/* + * 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. + */ +void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) +{ + curlassert(dns && (dns->inuse>0)); + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns->inuse--; + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); +} + +/* + * File-internal: free a cache dns entry. + */ +static void freednsentry(void *freethis) +{ + struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis; + + Curl_freeaddrinfo(p->addr); + + free(p); +} + +/* + * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it. + */ +struct curl_hash *Curl_mk_dnscache(void) +{ + return Curl_hash_alloc(7, freednsentry); +} + +#ifdef CURLRES_ADDRINFO_COPY + +/* align on even 64bit boundaries */ +#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7))) + +/* + * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and + * returns a pointer to the malloc()ed copy. You need to call free() on the + * returned buffer when you're done with it. + */ +Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port) +{ + const struct hostent *orig = org; + + return Curl_he2ai(orig, port); +} +#endif /* CURLRES_ADDRINFO_COPY */ + +/*********************************************************************** + * Only for plain-ipv4 and c-ares builds + **********************************************************************/ + +#if defined(CURLRES_IPV4) || defined(CURLRES_ARES) +/* + * This is a function for freeing name information in a protocol independent + * way. + */ +void Curl_freeaddrinfo(Curl_addrinfo *ai) +{ + Curl_addrinfo *next; + + /* walk over the list and free all entries */ + while(ai) { + next = ai->ai_next; + free(ai); + ai = next; + } +} + +struct namebuf { + struct hostent hostentry; + char *h_addr_list[2]; + struct in_addr addrentry; + char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */ +}; + +/* + * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter + * together with a pointer to the string version of the address, and it + * returns a Curl_addrinfo chain filled in correctly with information for this + * address/host. + * + * The input parameters ARE NOT checked for validity but they are expected + * to have been checked already when this is called. + */ +Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port) +{ + Curl_addrinfo *ai; + struct hostent *h; + struct in_addr *addrentry; + struct namebuf buffer; + struct namebuf *buf = &buffer; + + h = &buf->hostentry; + h->h_addr_list = &buf->h_addr_list[0]; + addrentry = &buf->addrentry; +#ifdef _CRAY + /* On UNICOS, s_addr is a bit field and for some reason assigning to it + * doesn't work. There must be a better fix than this ugly hack. + */ + memcpy(addrentry, &num, SIZEOF_in_addr); +#else + addrentry->s_addr = num; +#endif + h->h_addr_list[0] = (char*)addrentry; + h->h_addr_list[1] = NULL; + h->h_addrtype = AF_INET; + h->h_length = sizeof(*addrentry); + h->h_name = &buf->h_name[0]; + h->h_aliases = NULL; + + /* Now store the dotted version of the address */ + snprintf((char *)h->h_name, 16, "%s", hostname); + + ai = Curl_he2ai(h, port); + + return ai; +} +#endif + + diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h new file mode 100644 index 0000000..e6d63ca --- /dev/null +++ b/Utilities/cmcurl/lib/hostip.h @@ -0,0 +1,271 @@ +#ifndef __HOSTIP_H +#define __HOSTIP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include "hash.h" + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t uint32_t +#endif + +/* + * Setup comfortable CURLRES_* defines to use in the host*.c sources. + */ + +#ifdef USE_ARES +#define CURLRES_ASYNCH +#define CURLRES_ARES +#endif + +#ifdef USE_THREADING_GETHOSTBYNAME +#define CURLRES_ASYNCH +#define CURLRES_THREADED +#endif + +#ifdef USE_THREADING_GETADDRINFO +#define CURLRES_ASYNCH +#define CURLRES_THREADED +#endif + +#ifdef ENABLE_IPV6 +#define CURLRES_IPV6 +#else +#define CURLRES_IPV4 +#endif + +#if defined(CURLRES_IPV4) || defined(CURLRES_ARES) +#if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH) +/* If built for ipv4 and missing gethostbyname_r(), or if using async name + resolve, we need the Curl_addrinfo_copy() function (which itself needs the + Curl_he2ai() function)) */ +#define CURLRES_ADDRINFO_COPY +#endif +#endif /* IPv4/ares-only */ + +#ifndef CURLRES_ASYNCH +#define CURLRES_SYNCH +#endif + +#ifndef USE_LIBIDN +#define CURLRES_IDN +#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 + * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes! + */ +#define CURL_HOSTENT_SIZE 9000 + +#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this + many seconds for a name resolve */ + +#ifdef CURLRES_ARES +#define CURL_ASYNC_SUCCESS ARES_SUCCESS +#else +#define CURL_ASYNC_SUCCESS CURLE_OK +#define ares_cancel(x) do {} while(0) +#define ares_destroy(x) do {} while(0) +#endif + +/* + * Curl_addrinfo MUST be used for all name resolved info. + */ +#ifdef CURLRES_IPV6 +typedef struct addrinfo Curl_addrinfo; +#else +/* OK, so some ipv4-only include tree probably have the addrinfo struct, but + to work even on those that don't, we provide our own look-alike! */ +struct Curl_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */ + char *ai_canonname; + struct sockaddr *ai_addr; + struct Curl_addrinfo *ai_next; +}; +typedef struct Curl_addrinfo Curl_addrinfo; +#endif + +struct addrinfo; +struct hostent; +struct SessionHandle; +struct connectdata; + +void Curl_global_host_cache_init(void); +void Curl_global_host_cache_dtor(void); +struct curl_hash *Curl_global_host_cache_get(void); + +#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache) + +struct Curl_dns_entry { + Curl_addrinfo *addr; + time_t timestamp; + long inuse; /* use-counter, make very sure you decrease this + when you're done using the address you received */ +}; + +/* + * Curl_resolv() returns an entry with the info for the specified host + * and port. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! + */ +/* return codes */ +#define CURLRESOLV_ERROR -1 +#define CURLRESOLV_RESOLVED 0 +#define CURLRESOLV_PENDING 1 +int Curl_resolv(struct connectdata *conn, const char *hostname, + int port, struct Curl_dns_entry **dnsentry); + +/* + * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've + * been set and returns TRUE if they are OK. + */ +bool Curl_ipvalid(struct SessionHandle *data); + +/* + * Curl_getaddrinfo() is the generic low-level name resolve API within this + * source file. There are several versions of this function - for different + * name resolve layers (selected at build-time). They all take this same set + * of arguments + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp); + +CURLcode Curl_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **dns); +CURLcode Curl_wait_for_resolv(struct connectdata *conn, + struct Curl_dns_entry **dnsentry); + +/* Curl_resolv_getsock() is a generic function that exists in multiple + versions depending on what name resolve technology we've built to use. The + function is called from the multi_getsock() function. 'sock' is a pointer + to an array to hold the file descriptors, with 'numsock' being the size of + that array (in number of entries). This function is supposed to return + bitmask indicating what file descriptors (referring to array indexes in the + 'sock' array) to wait for, read/write. */ +int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *sock, + int numsocks); + +/* unlock a previously resolved dns entry */ +void Curl_resolv_unlock(struct SessionHandle *data, + struct Curl_dns_entry *dns); + +/* for debugging purposes only: */ +void Curl_scan_cache_used(void *user, void *ptr); + +/* free name info */ +void Curl_freeaddrinfo(Curl_addrinfo *freeaddr); + +/* make a new dns cache and return the handle */ +struct curl_hash *Curl_mk_dnscache(void); + +/* prune old entries from the DNS cache */ +void Curl_hostcache_prune(struct SessionHandle *data); + +/* Return # of adresses in a Curl_addrinfo struct */ +int Curl_num_addresses (const Curl_addrinfo *addr); + +#ifdef CURLDEBUG +void curl_dofreeaddrinfo(struct addrinfo *freethis, + int line, const char *source); +int curl_dogetaddrinfo(const char *hostname, const char *service, + struct addrinfo *hints, + struct addrinfo **result, + int line, const char *source); +#ifdef HAVE_GETNAMEINFO +int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, + GETNAMEINFO_TYPE_ARG2 salen, + char *host, GETNAMEINFO_TYPE_ARG46 hostlen, + char *serv, GETNAMEINFO_TYPE_ARG46 servlen, + GETNAMEINFO_TYPE_ARG7 flags, + int line, const char *source); +#endif +#endif + +/* This is the callback function that is used when we build with asynch + resolve, ipv4 */ +CURLcode Curl_addrinfo4_callback(void *arg, + int status, + struct hostent *hostent); +/* This is the callback function that is used when we build with asynch + resolve, ipv6 */ +CURLcode Curl_addrinfo6_callback(void *arg, + int status, + struct addrinfo *ai); + + +/* [ipv4/ares only] Creates a Curl_addrinfo struct from a numerical-only IP + address */ +Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port); + +/* [ipv4/ares only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain + and returns it */ +Curl_addrinfo *Curl_he2ai(const struct hostent *, int port); + +/* Clone a Curl_addrinfo struct, works protocol independently */ +Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port); + +/* + * Curl_printable_address() returns a printable version of the 1st address + * given in the 'ip' argument. The result will be stored in the buf that is + * bufsize bytes big. + */ +const char *Curl_printable_address(const Curl_addrinfo *ip, + char *buf, size_t bufsize); + +/* + * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. + * + * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. + */ +struct Curl_dns_entry * +Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, + const char *hostname, int port); + +/* + * Curl_destroy_thread_data() cleans up async resolver data. + * Complementary of ares_destroy. + */ +struct Curl_async; /* forward-declaration */ +void Curl_destroy_thread_data(struct Curl_async *async); + +#ifndef INADDR_NONE +#define CURL_INADDR_NONE (in_addr_t) ~0 +#else +#define CURL_INADDR_NONE INADDR_NONE +#endif + + + + +#endif diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c new file mode 100644 index 0000000..877baa2 --- /dev/null +++ b/Utilities/cmcurl/lib/hostip4.c @@ -0,0 +1,389 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "inet_pton.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/*********************************************************************** + * Only for plain-ipv4 builds + **********************************************************************/ +#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */ +/* + * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've + * been set and returns TRUE if they are OK. + */ +bool Curl_ipvalid(struct SessionHandle *data) +{ + if(data->set.ip_version == CURL_IPRESOLVE_V6) + /* an ipv6 address was requested and we can't get/use one */ + return FALSE; + + return TRUE; /* OK, proceed */ +} + +#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */ + +/* + * Curl_getaddrinfo() - the ipv4 synchronous version. + * + * The original code to this function was from the Dancer source code, written + * by Bjorn Reese, it has since been patched and modified considerably. + * + * gethostbyname_r() is the thread-safe version of the gethostbyname() + * function. When we build for plain IPv4, we attempt to use this + * function. There are _three_ different gethostbyname_r() versions, and we + * 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 + * flavours have thread-safe versions of the plain gethostbyname() etc. + * + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + Curl_addrinfo *ai = NULL; + struct hostent *h = NULL; + in_addr_t in; + struct SessionHandle *data = conn->data; + struct hostent *buf = NULL; + + (void)port; /* unused in IPv4 code */ + + *waitp = 0; /* don't wait, we act synchronously */ + + if(1 == Curl_inet_pton(AF_INET, hostname, &in)) + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(in, hostname, port); + +#if defined(HAVE_GETHOSTBYNAME_R) + /* + * gethostbyname_r() is the preferred resolve function for many platforms. + * Since there are three different versions of it, the following code is + * somewhat #ifdef-ridden. + */ + else { + int h_errnop; + int res=ERANGE; + + buf = (struct hostent *)calloc(CURL_HOSTENT_SIZE, 1); + if(!buf) + return NULL; /* major failure */ + /* + * The clearing of the buffer is a workaround for a gethostbyname_r bug in + * qnx nto and it is also _required_ for some of these functions on some + * platforms. + */ + +#ifdef HAVE_GETHOSTBYNAME_R_5 + /* Solaris, IRIX and more */ + (void)res; /* prevent compiler warning */ + h = gethostbyname_r(hostname, + (struct hostent *)buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h_errnop); + + /* If the buffer is too small, it returns NULL and sets errno to + * ERANGE. The errno is thread safe if this is compiled with + * -D_REENTRANT as then the 'errno' variable is a macro defined to get + * used properly for threads. + */ + + if(h) { + ; + } + else +#endif /* HAVE_GETHOSTBYNAME_R_5 */ +#ifdef HAVE_GETHOSTBYNAME_R_6 + /* Linux */ + + res=gethostbyname_r(hostname, + (struct hostent *)buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h, /* DIFFERENCE */ + &h_errnop); + /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a + * sudden this function returns EAGAIN if the given buffer size is too + * small. Previous versions are known to return ERANGE for the same + * problem. + * + * 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. + * + * For now, we do that and thus we may call the function repeatedly and + * fail for older glibc versions that return EAGAIN, until we run out of + * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). + * + * If anyone has a better fix, please tell us! + * + * ------------------------------------------------------------------- + * + * On October 23rd 2003, Dan C dug up more details on the mysteries of + * 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 can't + * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 + * (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 + * thread-safe variable. + */ + + if(!h) /* failure */ +#endif/* HAVE_GETHOSTBYNAME_R_6 */ +#ifdef HAVE_GETHOSTBYNAME_R_3 + /* AIX, Digital Unix/Tru64, HPUX 10, more? */ + + /* 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 + * our caching system breaks down horribly. Luckily for us though, AIX 4.3 + * and more recent versions have a "completely thread-safe"[*] libc where + * all the data is stored in thread-specific memory areas making calls to + * the plain old gethostbyname() work fine even for multi-threaded + * programs. + * + * This AIX 4.3 or later detection is all made in the configure script. + * + * Troels Walsted Hansen helped us work this out on March 3rd, 2003. + * + * [*] = much later we've found out that it isn't at all "completely + * thread-safe", but at least the gethostbyname() function is. + */ + + if(CURL_HOSTENT_SIZE >= + (sizeof(struct hostent)+sizeof(struct hostent_data))) { + + /* August 22nd, 2000: Albert Chin-A-Young brought an updated version + * that should work! September 20: Richard Prescott worked on the buffer + * size dilemma. + */ + + res = gethostbyname_r(hostname, + (struct hostent *)buf, + (struct hostent_data *)((char *)buf + + sizeof(struct hostent))); + h_errnop= errno; /* we don't deal with this, but set it anyway */ + } + else + res = -1; /* failure, too smallish buffer size */ + + if(!res) { /* success */ + + h = buf; /* result expected in h */ + + /* This is the worst kind of the different gethostbyname_r() interfaces. + * 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 + * memory area to the actually used amount. + */ + } + else +#endif /* HAVE_GETHOSTBYNAME_R_3 */ + { + infof(data, "gethostbyname_r(2) failed for %s\n", hostname); + h = NULL; /* set return code to NULL */ + free(buf); + } +#else /* HAVE_GETHOSTBYNAME_R */ + /* + * Here is code for platforms that don't have gethostbyname_r() or for + * which the gethostbyname() is the preferred() function. + */ + else { + h = gethostbyname(hostname); + if (!h) + infof(data, "gethostbyname(2) failed for %s\n", hostname); +#endif /*HAVE_GETHOSTBYNAME_R */ + } + + if(h) { + ai = Curl_he2ai(h, port); + + if (buf) /* used a *_r() function */ + free(buf); + } + + return ai; +} + +#endif /* CURLRES_SYNCH */ +#endif /* CURLRES_IPV4 */ + +/* + * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct. + * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6 + * stacks, but for all hosts and environments. + * + * Curl_addrinfo defined in "lib/hostip.h" + * + * struct Curl_addrinfo { + * int ai_flags; + * int ai_family; + * int ai_socktype; + * int ai_protocol; + * socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * + * char *ai_canonname; + * struct sockaddr *ai_addr; + * struct Curl_addrinfo *ai_next; + * }; + * + * hostent defined in + * + * struct hostent { + * char *h_name; + * char **h_aliases; + * int h_addrtype; + * int h_length; + * char **h_addr_list; + * }; + * + * for backward compatibility: + * + * #define h_addr h_addr_list[0] + */ + +Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port) +{ + Curl_addrinfo *ai; + Curl_addrinfo *prevai = NULL; + Curl_addrinfo *firstai = NULL; + struct sockaddr_in *addr; + int i; + struct in_addr *curr; + + if(!he) + /* no input == no output! */ + return NULL; + + for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]) != NULL; i++) { + + ai = calloc(1, sizeof(Curl_addrinfo) + sizeof(struct sockaddr_in)); + + if(!ai) + break; + + if(!firstai) + /* store the pointer we want to return from this function */ + firstai = ai; + + if(prevai) + /* make the previous entry point to this */ + prevai->ai_next = ai; + + ai->ai_family = AF_INET; /* we only support this */ + + /* we return all names as STREAM, so when using this address for TFTP + the type must be ignored and conn->socktype be used instead! */ + ai->ai_socktype = SOCK_STREAM; + + ai->ai_addrlen = sizeof(struct sockaddr_in); + /* make the ai_addr point to the address immediately following this struct + and use that area to store the address */ + ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo)); + + /* leave the rest of the struct filled with zero */ + + addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */ + + memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr)); + addr->sin_family = he->h_addrtype; + addr->sin_port = htons((unsigned short)port); + + prevai = ai; + } + return firstai; +} + diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c new file mode 100644 index 0000000..c8bbdb5 --- /dev/null +++ b/Utilities/cmcurl/lib/hostip6.c @@ -0,0 +1,306 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "inet_pton.h" +#include "connect.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/*********************************************************************** + * Only for ipv6-enabled builds + **********************************************************************/ +#ifdef CURLRES_IPV6 +#ifndef CURLRES_ARES +/* + * This is a wrapper function for freeing name information in a protocol + * independent way. This takes care of using the appropriate underlaying + * function. + */ +void Curl_freeaddrinfo(Curl_addrinfo *p) +{ + freeaddrinfo(p); +} + +#ifdef CURLRES_ASYNCH +/* + * Curl_addrinfo_copy() is used by the asynch callback to copy a given + * address. But this is an ipv6 build and then we don't copy the address, we + * just return the same pointer! + */ +Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port) +{ + (void) port; + return (Curl_addrinfo*)orig; +} +#endif /* CURLRES_ASYNCH */ +#endif /* CURLRES_ARES */ + +#ifdef CURLDEBUG +/* These are 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 didn't wanna include in memdebug.c + */ +int curl_dogetaddrinfo(const char *hostname, const char *service, + struct addrinfo *hints, + struct addrinfo **result, + int line, const char *source) +{ + int res=(getaddrinfo)(hostname, service, hints, result); + if(0 == res) { + /* success */ + if(logfile) + fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n", + source, line, (void *)*result); + } + else { + if(logfile) + fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n", + source, line); + } + return res; +} + +/* + * For CURLRES_ARS, this should be written using ares_gethostbyaddr() + * (ignoring the fact c-ares doesn't return 'serv'). + */ +#ifdef HAVE_GETNAMEINFO +int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, + GETNAMEINFO_TYPE_ARG2 salen, + char *host, GETNAMEINFO_TYPE_ARG46 hostlen, + char *serv, GETNAMEINFO_TYPE_ARG46 servlen, + GETNAMEINFO_TYPE_ARG7 flags, + int line, const char *source) +{ + int res = (getnameinfo)(sa, salen, + host, hostlen, + serv, servlen, + flags); + if(0 == res) { + /* success */ + if(logfile) + fprintf(logfile, "GETNAME %s:%d getnameinfo()\n", + source, line); + } + else { + if(logfile) + fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n", + source, line, res); + } + return res; +} +#endif + +void curl_dofreeaddrinfo(struct addrinfo *freethis, + int line, const char *source) +{ + (freeaddrinfo)(freethis); + if(logfile) + fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n", + source, line, (void *)freethis); +} +#endif /* CURLDEBUG */ + +/* + * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've + * been set and returns TRUE if they are OK. + */ +bool Curl_ipvalid(struct SessionHandle *data) +{ + if(data->set.ip_version == CURL_IPRESOLVE_V6) { + /* see if we have an IPv6 stack */ + curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == CURL_SOCKET_BAD) + /* an ipv6 address was requested and we can't get/use one */ + return FALSE; + sclose(s); + } + return TRUE; +} + +#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES) + +#ifdef DEBUG_ADDRINFO +static void dump_addrinfo(struct connectdata *conn, const struct addrinfo *ai) +{ + printf("dump_addrinfo:\n"); + for ( ; ai; ai = ai->ai_next) { + char buf[INET6_ADDRSTRLEN]; + + printf(" fam %2d, CNAME %s, ", + ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); + if (Curl_printable_address(ai, buf, sizeof(buf))) + printf("%s\n", buf); + else + printf("failed; %s\n", Curl_strerror(conn, Curl_sockerrno())); + } +} +#else +#define dump_addrinfo(x,y) +#endif + +/* + * Curl_getaddrinfo() when built ipv6-enabled (non-threading and + * non-ares version). + * + * Returns name information about the given hostname and port number. If + * successful, the 'addrinfo' is returned and the forth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + struct addrinfo hints, *res; + int error; + char sbuf[NI_MAXSERV]; + char *sbufptr = NULL; + char addrbuf[128]; + curl_socket_t s; + int pf; + struct SessionHandle *data = conn->data; + + *waitp=0; /* don't wait, we have the response now */ + + /* see if we have an IPv6 stack */ + s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == CURL_SOCKET_BAD) { + /* Some non-IPv6 stacks have been found to make very slow name resolves + * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if + * the stack seems to be a non-ipv6 one. */ + + pf = PF_INET; + } + else { + /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest + * possible checks. And close the socket again. + */ + sclose(s); + + /* + * Check if a more limited name resolve has been requested. + */ + switch(data->set.ip_version) { + case CURL_IPRESOLVE_V4: + pf = PF_INET; + break; + case CURL_IPRESOLVE_V6: + pf = PF_INET6; + break; + default: + pf = PF_UNSPEC; + break; + } + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = pf; + hints.ai_socktype = conn->socktype; + + if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || + (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { + /* the given address is numerical only, prevent a reverse lookup */ + hints.ai_flags = AI_NUMERICHOST; + } +#if 0 /* removed nov 8 2005 before 7.15.1 */ + else + hints.ai_flags = AI_CANONNAME; +#endif + + if(port) { + snprintf(sbuf, sizeof(sbuf), "%d", port); + sbufptr=sbuf; + } + error = getaddrinfo(hostname, sbufptr, &hints, &res); + if (error) { + infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port); + return NULL; + } + + dump_addrinfo(conn, res); + + return res; +} +#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */ +#endif /* ipv6 */ + diff --git a/Utilities/cmcurl/lib/hostsyn.c b/Utilities/cmcurl/lib/hostsyn.c new file mode 100644 index 0000000..2f816b8 --- /dev/null +++ b/Utilities/cmcurl/lib/hostsyn.c @@ -0,0 +1,138 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/*********************************************************************** + * Only for builds using synchronous name resolves + **********************************************************************/ +#ifdef CURLRES_SYNCH + +/* + * Curl_wait_for_resolv() for synch-builds. Curl_resolv() can never return + * wait==TRUE, so this function will never be called. If it still gets called, + * we return failure at once. + * + * We provide this function only to allow multi.c to remain unaware if we are + * doing asynch resolves or not. + */ +CURLcode Curl_wait_for_resolv(struct connectdata *conn, + struct Curl_dns_entry **entry) +{ + (void)conn; + *entry=NULL; + return CURLE_COULDNT_RESOLVE_HOST; +} + +/* + * This function will never be called when synch-built. If it still gets + * called, we return failure at once. + * + * We provide this function only to allow multi.c to remain unaware if we are + * doing asynch resolves or not. + */ +CURLcode Curl_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **dns) +{ + (void)conn; + *dns = NULL; + + return CURLE_COULDNT_RESOLVE_HOST; +} + +/* + * We just return OK, this function is never actually used for synch builds. + * It is present here to keep #ifdefs out from multi.c + */ + +int Curl_resolv_getsock(struct connectdata *conn, + curl_socket_t *sock, + int numsocks) +{ + (void)conn; + (void)sock; + (void)numsocks; + + return 0; /* no bits since we don't use any socks */ +} + +#endif /* truly sync */ diff --git a/Utilities/cmcurl/lib/hostthre.c b/Utilities/cmcurl/lib/hostthre.c new file mode 100644 index 0000000..12e31ea --- /dev/null +++ b/Utilities/cmcurl/lib/hostthre.c @@ -0,0 +1,840 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef VMS +#include +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "multiif.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "inet_ntop.h" + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +#if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX) +#pragma message ("No _beginthreadex() available in this RTL") +#endif + +/*********************************************************************** + * Only for Windows threaded name resolves builds + **********************************************************************/ +#ifdef CURLRES_THREADED + +/* This function is used to init a threaded resolve */ +static bool init_resolve_thread(struct connectdata *conn, + const char *hostname, int port, + const Curl_addrinfo *hints); + +#ifdef CURLRES_IPV4 + #define THREAD_FUNC gethostbyname_thread + #define THREAD_NAME "gethostbyname_thread" +#else + #define THREAD_FUNC getaddrinfo_thread + #define THREAD_NAME "getaddrinfo_thread" +#endif + +#if defined(DEBUG_THREADING_GETHOSTBYNAME) || \ + defined(DEBUG_THREADING_GETADDRINFO) +/* If this is defined, provide tracing */ +#define TRACE(args) \ + do { trace_it("%u: ", __LINE__); trace_it args; } while (0) + +static void trace_it (const char *fmt, ...) +{ + static int do_trace = -1; + va_list args; + + if (do_trace == -1) { + const char *env = getenv("CURL_TRACE"); + do_trace = (env && atoi(env) > 0); + } + if (!do_trace) + return; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + fflush (stderr); + va_end (args); +} +#else +#define TRACE(x) +#endif + +#ifdef DEBUG_THREADING_GETADDRINFO +static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai) +{ + TRACE(("dump_addrinfo:\n")); + for ( ; ai; ai = ai->ai_next) { + char buf [INET6_ADDRSTRLEN]; + + trace_it(" fam %2d, CNAME %s, ", + ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); + if (Curl_printable_address(ai, buf, sizeof(buf))) + trace_it("%s\n", buf); + else + trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError())); + } +} +#endif + +struct thread_data { + HANDLE thread_hnd; + unsigned thread_id; + DWORD thread_status; + curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */ + HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */ + HANDLE event_resolved; /* marks that the thread obtained the information */ + HANDLE event_thread_started; /* marks that the thread has initialized and + started */ + HANDLE mutex_terminate; /* serializes access to flag_terminate */ + HANDLE event_terminate; /* flag for thread to terminate instead of calling + callbacks */ +#ifdef CURLRES_IPV6 + struct addrinfo hints; +#endif +}; + +/* Data for synchronization between resolver thread and its parent */ +struct thread_sync_data { + HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */ + HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */ + HANDLE event_terminate; /* thread_data.event_terminate duplicate */ + char * hostname; /* hostname to resolve, Curl_async.hostname + duplicate */ +}; + +/* Destroy resolver thread synchronization data */ +static +void destroy_thread_sync_data(struct thread_sync_data * tsd) +{ + if (tsd->hostname) { + free(tsd->hostname); + tsd->hostname = NULL; + } + if (tsd->event_terminate) { + CloseHandle(tsd->event_terminate); + tsd->event_terminate = NULL; + } + if (tsd->mutex_terminate) { + CloseHandle(tsd->mutex_terminate); + tsd->mutex_terminate = NULL; + } + if (tsd->mutex_waiting) { + CloseHandle(tsd->mutex_waiting); + tsd->mutex_waiting = NULL; + } +} + +/* Initialize resolver thread synchronization data */ +static +BOOL init_thread_sync_data(struct thread_data * td, + char * hostname, + struct thread_sync_data * tsd) +{ + HANDLE curr_proc = GetCurrentProcess(); + + memset(tsd, 0, sizeof(*tsd)); + if (!DuplicateHandle(curr_proc, td->mutex_waiting, + curr_proc, &tsd->mutex_waiting, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + /* failed to duplicate the mutex, no point in continuing */ + destroy_thread_sync_data(tsd); + return FALSE; + } + if (!DuplicateHandle(curr_proc, td->mutex_terminate, + curr_proc, &tsd->mutex_terminate, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + /* failed to duplicate the mutex, no point in continuing */ + destroy_thread_sync_data(tsd); + return FALSE; + } + if (!DuplicateHandle(curr_proc, td->event_terminate, + curr_proc, &tsd->event_terminate, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + /* failed to duplicate the event, no point in continuing */ + destroy_thread_sync_data(tsd); + return FALSE; + } + /* Copying hostname string because original can be destroyed by parent + * thread during gethostbyname execution. + */ + tsd->hostname = strdup(hostname); + if (!tsd->hostname) { + /* Memory allocation failed */ + destroy_thread_sync_data(tsd); + return FALSE; + } + return TRUE; +} + +/* acquire resolver thread synchronization */ +static +BOOL acquire_thread_sync(struct thread_sync_data * tsd) +{ + /* is the thread initiator still waiting for us ? */ + if (WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) { + /* yes, it is */ + + /* Waiting access to event_terminate */ + if (WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) { + /* Something went wrong - now just ignoring */ + } + else { + if (WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) { + /* Parent thread signaled us to terminate. + * This means that all data in conn->async is now destroyed + * and we cannot use it. + */ + } + else { + return TRUE; + } + } + } + return FALSE; +} + +/* release resolver thread synchronization */ +static +void release_thread_sync(struct thread_sync_data * tsd) +{ + ReleaseMutex(tsd->mutex_terminate); +} + +#if defined(CURLRES_IPV4) +/* + * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback + * and then exits. + * + * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on + * it. + */ +static unsigned __stdcall gethostbyname_thread (void *arg) +{ + struct connectdata *conn = (struct connectdata*) arg; + struct thread_data *td = (struct thread_data*) conn->async.os_specific; + struct hostent *he; + int rc = 0; + + /* Duplicate the passed mutex and event handles. + * This allows us to use it even after the container gets destroyed + * due to a resolver timeout. + */ + struct thread_sync_data tsd = { 0,0,0,NULL }; + if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) { + /* thread synchronization data initialization failed */ + return (unsigned)-1; + } + + WSASetLastError (conn->async.status = NO_DATA); /* pending status */ + + /* Signaling that we have initialized all copies of data and handles we + need */ + SetEvent(td->event_thread_started); + + he = gethostbyname (tsd.hostname); + + /* is parent thread waiting for us and are we able to access conn members? */ + if (acquire_thread_sync(&tsd)) { + /* Mark that we have obtained the information, and that we are calling + * back with it. */ + SetEvent(td->event_resolved); + if (he) { + rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he); + } + else { + rc = Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL); + } + TRACE(("Winsock-error %d, addr %s\n", conn->async.status, + he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown")); + release_thread_sync(&tsd); + } + + /* clean up */ + destroy_thread_sync_data(&tsd); + + return (rc); + /* An implicit _endthreadex() here */ +} + +#elif defined(CURLRES_IPV6) + +/* + * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then + * exits. + * + * For builds without ARES, but with ENABLE_IPV6, create a resolver thread + * and wait on it. + */ +static unsigned __stdcall getaddrinfo_thread (void *arg) +{ + struct connectdata *conn = (struct connectdata*) arg; + struct thread_data *td = (struct thread_data*) conn->async.os_specific; + struct addrinfo *res; + char service [NI_MAXSERV]; + int rc; + struct addrinfo hints = td->hints; + + /* Duplicate the passed mutex handle. + * This allows us to use it even after the container gets destroyed + * due to a resolver timeout. + */ + struct thread_sync_data tsd = { 0,0,0,NULL }; + if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) { + /* thread synchronization data initialization failed */ + return -1; + } + + itoa(conn->async.port, service, 10); + + WSASetLastError(conn->async.status = NO_DATA); /* pending status */ + + /* Signaling that we have initialized all copies of data and handles we + need */ + SetEvent(td->event_thread_started); + + rc = getaddrinfo(tsd.hostname, service, &hints, &res); + + /* is parent thread waiting for us and are we able to access conn members? */ + if (acquire_thread_sync(&tsd)) { + /* Mark that we have obtained the information, and that we are calling + back with it. */ + SetEvent(td->event_resolved); + + if (rc == 0) { +#ifdef DEBUG_THREADING_GETADDRINFO + dump_addrinfo (conn, res); +#endif + rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res); + } + else { + rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL); + TRACE(("Winsock-error %d, no address\n", conn->async.status)); + } + release_thread_sync(&tsd); + } + + /* clean up */ + destroy_thread_sync_data(&tsd); + + return (rc); + /* An implicit _endthreadex() here */ +} +#endif + +/* + * Curl_destroy_thread_data() cleans up async resolver data and thread handle. + * Complementary of ares_destroy. + */ +void Curl_destroy_thread_data (struct Curl_async *async) +{ + if (async->hostname) + free(async->hostname); + + if (async->os_specific) { + struct thread_data *td = (struct thread_data*) async->os_specific; + curl_socket_t sock = td->dummy_sock; + + if (td->mutex_terminate && td->event_terminate) { + /* Signaling resolver thread to terminate */ + if (WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) { + SetEvent(td->event_terminate); + ReleaseMutex(td->mutex_terminate); + } + else { + /* Something went wrong - just ignoring it */ + } + } + + if (td->mutex_terminate) + CloseHandle(td->mutex_terminate); + if (td->event_terminate) + CloseHandle(td->event_terminate); + if (td->event_thread_started) + CloseHandle(td->event_thread_started); + + if (sock != CURL_SOCKET_BAD) + sclose(sock); + + /* destroy the synchronization objects */ + if (td->mutex_waiting) + CloseHandle(td->mutex_waiting); + td->mutex_waiting = NULL; + if (td->event_resolved) + CloseHandle(td->event_resolved); + + if (td->thread_hnd) + CloseHandle(td->thread_hnd); + + free(async->os_specific); + } + async->hostname = NULL; + async->os_specific = NULL; +} + +/* + * init_resolve_thread() starts a new thread that performs the actual + * resolve. This function returns before the resolve is done. + * + * Returns FALSE in case of failure, otherwise TRUE. + */ +static bool init_resolve_thread (struct connectdata *conn, + const char *hostname, int port, + const Curl_addrinfo *hints) +{ + struct thread_data *td = calloc(sizeof(*td), 1); + HANDLE thread_and_event[2] = {0}; + + if (!td) { + SetLastError(ENOMEM); + return FALSE; + } + + Curl_safefree(conn->async.hostname); + conn->async.hostname = strdup(hostname); + if (!conn->async.hostname) { + free(td); + SetLastError(ENOMEM); + return FALSE; + } + + conn->async.port = port; + conn->async.done = FALSE; + conn->async.status = 0; + conn->async.dns = NULL; + conn->async.os_specific = (void*) td; + td->dummy_sock = CURL_SOCKET_BAD; + + /* Create the mutex used to inform the resolver thread that we're + * still waiting, and take initial ownership. + */ + td->mutex_waiting = CreateMutex(NULL, TRUE, NULL); + if (td->mutex_waiting == NULL) { + Curl_destroy_thread_data(&conn->async); + SetLastError(EAGAIN); + return FALSE; + } + + /* Create the event that the thread uses to inform us that it's + * done resolving. Do not signal it. + */ + td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL); + if (td->event_resolved == NULL) { + Curl_destroy_thread_data(&conn->async); + SetLastError(EAGAIN); + return FALSE; + } + /* Create the mutex used to serialize access to event_terminated + * between us and resolver thread. + */ + td->mutex_terminate = CreateMutex(NULL, FALSE, NULL); + if (td->mutex_terminate == NULL) { + Curl_destroy_thread_data(&conn->async); + SetLastError(EAGAIN); + return FALSE; + } + /* Create the event used to signal thread that it should terminate. + */ + td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL); + if (td->event_terminate == NULL) { + Curl_destroy_thread_data(&conn->async); + SetLastError(EAGAIN); + return FALSE; + } + /* Create the event used by thread to inform it has initialized its own data. + */ + td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL); + if (td->event_thread_started == NULL) { + Curl_destroy_thread_data(&conn->async); + SetLastError(EAGAIN); + return FALSE; + } + +#ifdef _WIN32_WCE + td->thread_hnd = (HANDLE) CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) THREAD_FUNC, + conn, 0, &td->thread_id); +#else + td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC, + conn, 0, &td->thread_id); +#endif + +#ifdef CURLRES_IPV6 + curlassert(hints); + td->hints = *hints; +#else + (void) hints; +#endif + + if (!td->thread_hnd) { +#ifdef _WIN32_WCE + TRACE(("CreateThread() failed; %s\n", Curl_strerror(conn,GetLastError()))); +#else + SetLastError(errno); + TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno))); +#endif + Curl_destroy_thread_data(&conn->async); + return FALSE; + } + /* Waiting until the thread will initialize its data or it will exit due errors. + */ + thread_and_event[0] = td->thread_hnd; + thread_and_event[1] = td->event_thread_started; + if (WaitForMultipleObjects(sizeof(thread_and_event) / + sizeof(thread_and_event[0]), + (const HANDLE*)thread_and_event, FALSE, + INFINITE) == WAIT_FAILED) { + /* The resolver thread has been created, + * most probably it works now - ignoring this "minor" error + */ + } + /* This socket is only to keep Curl_resolv_fdset() and select() happy; + * should never become signalled for read/write since it's unbound but + * Windows needs atleast 1 socket in select(). + */ + td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0); + return TRUE; +} + + +/* + * Curl_wait_for_resolv() waits for a resolve to finish. This function should + * be avoided since using this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * This is the version for resolves-in-a-thread. + */ +CURLcode Curl_wait_for_resolv(struct connectdata *conn, + struct Curl_dns_entry **entry) +{ + struct thread_data *td = (struct thread_data*) conn->async.os_specific; + struct SessionHandle *data = conn->data; + long timeout; + DWORD status, ticks; + CURLcode rc; + + curlassert (conn && td); + + /* now, see if there's a connect timeout or a regular timeout to + use instead of the default one */ + timeout = + conn->data->set.connecttimeout ? conn->data->set.connecttimeout : + conn->data->set.timeout ? conn->data->set.timeout : + CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */ + ticks = GetTickCount(); + + /* wait for the thread to resolve the name */ + status = WaitForSingleObject(td->event_resolved, 1000UL*timeout); + + /* mark that we are now done waiting */ + ReleaseMutex(td->mutex_waiting); + + /* close our handle to the mutex, no point in hanging on to it */ + CloseHandle(td->mutex_waiting); + td->mutex_waiting = NULL; + + /* close the event handle, it's useless now */ + CloseHandle(td->event_resolved); + td->event_resolved = NULL; + + /* has the resolver thread succeeded in resolving our query ? */ + if (status == WAIT_OBJECT_0) { + /* wait for the thread to exit, it's in the callback sequence */ + if (WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) { + TerminateThread(td->thread_hnd, 0); + conn->async.done = TRUE; + td->thread_status = (DWORD)-1; + TRACE(("%s() thread stuck?!, ", THREAD_NAME)); + } + else { + /* Thread finished before timeout; propagate Winsock error to this + * thread. 'conn->async.done = TRUE' is set in + * Curl_addrinfo4/6_callback(). + */ + WSASetLastError(conn->async.status); + GetExitCodeThread(td->thread_hnd, &td->thread_status); + TRACE(("%s() status %lu, thread retval %lu, ", + THREAD_NAME, status, td->thread_status)); + } + } + else { + conn->async.done = TRUE; + td->thread_status = (DWORD)-1; + TRACE(("%s() timeout, ", THREAD_NAME)); + } + + TRACE(("elapsed %lu ms\n", GetTickCount()-ticks)); + + if(entry) + *entry = conn->async.dns; + + rc = CURLE_OK; + + if (!conn->async.dns) { + /* a name was not resolved */ + if (td->thread_status == CURLE_OUT_OF_MEMORY) { + rc = CURLE_OUT_OF_MEMORY; + failf(data, "Could not resolve host: %s", curl_easy_strerror(rc)); + } + else if(conn->async.done) { + if(conn->bits.httpproxy) { + failf(data, "Could not resolve proxy: %s; %s", + conn->proxy.dispname, Curl_strerror(conn, conn->async.status)); + rc = CURLE_COULDNT_RESOLVE_PROXY; + } + else { + failf(data, "Could not resolve host: %s; %s", + conn->host.name, Curl_strerror(conn, conn->async.status)); + rc = CURLE_COULDNT_RESOLVE_HOST; + } + } + else if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) { + failf(data, "Resolving host timed out: %s", conn->host.name); + rc = CURLE_OPERATION_TIMEDOUT; + } + else + rc = CURLE_OPERATION_TIMEDOUT; + } + + Curl_destroy_thread_data(&conn->async); + + if(!conn->async.dns) + conn->bits.close = TRUE; + + return (rc); +} + +/* + * Curl_is_resolved() is called repeatedly to check if a previous name resolve + * request has completed. It should also make sure to time-out if the + * operation seems to take too long. + */ +CURLcode Curl_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **entry) +{ + *entry = NULL; + + if (conn->async.done) { + /* we're done */ + Curl_destroy_thread_data(&conn->async); + if (!conn->async.dns) { + TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n")); + return CURLE_COULDNT_RESOLVE_HOST; + } + *entry = conn->async.dns; + TRACE(("resolved okay, dns %p\n", *entry)); + } + return CURLE_OK; +} + +int Curl_resolv_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + const struct thread_data *td = + (const struct thread_data *) conn->async.os_specific; + + if (td && td->dummy_sock != CURL_SOCKET_BAD) { + if(numsocks) { + /* return one socket waiting for writable, even though this is just + a dummy */ + socks[0] = td->dummy_sock; + return GETSOCK_WRITESOCK(0); + } + } + return 0; +} + +#ifdef CURLRES_IPV4 +/* + * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6. + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + struct hostent *h = NULL; + struct SessionHandle *data = conn->data; + in_addr_t in; + + *waitp = 0; /* don't wait, we act synchronously */ + + in = inet_addr(hostname); + if (in != CURL_INADDR_NONE) + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(in, hostname, port); + + /* fire up a new resolver thread! */ + if (init_resolve_thread(conn, hostname, port, NULL)) { + *waitp = TRUE; /* please wait for the response */ + return NULL; + } + + /* fall-back to blocking version */ + infof(data, "init_resolve_thread() failed for %s; %s\n", + hostname, Curl_strerror(conn,GetLastError())); + + h = gethostbyname(hostname); + if (!h) { + infof(data, "gethostbyname(2) failed for %s:%d; %s\n", + hostname, port, Curl_strerror(conn,WSAGetLastError())); + return NULL; + } + return Curl_he2ai(h, port); +} +#endif /* CURLRES_IPV4 */ + +#ifdef CURLRES_IPV6 +/* + * Curl_getaddrinfo() - for Windows threading IPv6 enabled + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + struct addrinfo hints, *res; + int error; + char sbuf[NI_MAXSERV]; + curl_socket_t s; + int pf; + struct SessionHandle *data = conn->data; + + *waitp = FALSE; /* default to synch response */ + + /* see if we have an IPv6 stack */ + s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == CURL_SOCKET_BAD) { + /* Some non-IPv6 stacks have been found to make very slow name resolves + * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if + * the stack seems to be a non-ipv6 one. */ + + pf = PF_INET; + } + else { + /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest + * possible checks. And close the socket again. + */ + sclose(s); + + /* + * Check if a more limited name resolve has been requested. + */ + switch(data->set.ip_version) { + case CURL_IPRESOLVE_V4: + pf = PF_INET; + break; + case CURL_IPRESOLVE_V6: + pf = PF_INET6; + break; + default: + pf = PF_UNSPEC; + break; + } + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = pf; + hints.ai_socktype = conn->socktype; +#if 0 /* removed nov 8 2005 before 7.15.1 */ + hints.ai_flags = AI_CANONNAME; +#endif + itoa(port, sbuf, 10); + + /* fire up a new resolver thread! */ + if (init_resolve_thread(conn, hostname, port, &hints)) { + *waitp = TRUE; /* please wait for the response */ + return NULL; + } + + /* fall-back to blocking version */ + infof(data, "init_resolve_thread() failed for %s; %s\n", + hostname, Curl_strerror(conn,GetLastError())); + + error = getaddrinfo(hostname, sbuf, &hints, &res); + if (error) { + infof(data, "getaddrinfo() failed for %s:%d; %s\n", + hostname, port, Curl_strerror(conn,WSAGetLastError())); + return NULL; + } + return res; +} +#endif /* CURLRES_IPV6 */ +#endif /* CURLRES_THREADED */ diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c new file mode 100644 index 0000000..5405aac --- /dev/null +++ b/Utilities/cmcurl/lib/http.c @@ -0,0 +1,2422 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_HTTP +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef WIN32 +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_TIME_H +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "easyif.h" /* for Curl_convert_... prototypes */ +#include "formdata.h" +#include "progress.h" +#include "base64.h" +#include "cookie.h" +#include "strequal.h" +#include "sslgen.h" +#include "http_digest.h" +#include "http_ntlm.h" +#include "http_negotiate.h" +#include "url.h" +#include "share.h" +#include "hostip.h" +#include "http.h" +#include "memory.h" +#include "select.h" +#include "parsedate.h" /* for the week day and month names */ +#include "strtoofft.h" +#include "multiif.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * checkheaders() checks the linked list of custom HTTP headers for a + * particular header (prefix). + * + * Returns a pointer to the first matching header or NULL if none matched. + */ +static char *checkheaders(struct SessionHandle *data, const char *thisheader) +{ + struct curl_slist *head; + size_t thislen = strlen(thisheader); + + for(head = data->set.headers; head; head=head->next) { + if(strnequal(head->data, thisheader, thislen)) + return head->data; + } + return NULL; +} + +/* + * Curl_output_basic() sets up an Authorization: header (or the proxy version) + * for HTTP Basic authentication. + * + * Returns CURLcode. + */ +static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy) +{ + char *authorization; + struct SessionHandle *data=conn->data; + char **userp; + char *user; + char *pwd; + + if(proxy) { + userp = &conn->allocptr.proxyuserpwd; + user = conn->proxyuser; + pwd = conn->proxypasswd; + } + else { + userp = &conn->allocptr.userpwd; + user = conn->user; + pwd = conn->passwd; + } + + snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); + if(Curl_base64_encode(data, data->state.buffer, + strlen(data->state.buffer), + &authorization) > 0) { + if(*userp) + free(*userp); + *userp = aprintf( "%sAuthorization: Basic %s\r\n", + proxy?"Proxy-":"", + authorization); + free(authorization); + } + else + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} + +/* pickoneauth() selects the most favourable authentication method from the + * ones available and the ones we want. + * + * return TRUE if one was picked + */ +static bool pickoneauth(struct auth *pick) +{ + bool picked; + /* only deal with authentication we want */ + long avail = pick->avail & pick->want; + picked = TRUE; + + /* The order of these checks is highly relevant, as this will be the order + of preference in case of the existence of multiple accepted types. */ + if(avail & CURLAUTH_GSSNEGOTIATE) + pick->picked = CURLAUTH_GSSNEGOTIATE; + else if(avail & CURLAUTH_DIGEST) + pick->picked = CURLAUTH_DIGEST; + else if(avail & CURLAUTH_NTLM) + pick->picked = CURLAUTH_NTLM; + else if(avail & CURLAUTH_BASIC) + pick->picked = CURLAUTH_BASIC; + else { + pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ + picked = FALSE; + } + pick->avail = CURLAUTH_NONE; /* clear it here */ + + return picked; +} + +/* + * perhapsrewind() + * + * 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 perhapsrewind(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + struct HTTP *http = data->reqdata.proto.http; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + 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; + + bytessent = http->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 { + /* figure out how much data we are expected to send */ + switch(data->set.httpreq) { + case HTTPREQ_POST: + if(data->set.postfieldsize != -1) + expectsend = data->set.postfieldsize; + break; + case HTTPREQ_PUT: + if(data->set.infilesize != -1) + expectsend = data->set.infilesize; + break; + case HTTPREQ_POST_FORM: + expectsend = http->postsize; + break; + default: + break; + } + } + + conn->bits.rewindaftersend = FALSE; /* default */ + + if((expectsend == -1) || (expectsend > bytessent)) { + /* There is still data left to send */ + if((data->state.authproxy.picked == CURLAUTH_NTLM) || + (data->state.authhost.picked == CURLAUTH_NTLM)) { + if(((expectsend - bytessent) < 2000) || + (conn->ntlm.state != NTLMSTATE_NONE)) { + /* 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->bits.rewindaftersend = TRUE; + + 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 %" FORMAT_OFF_T + " bytes\n", (curl_off_t)(expectsend - bytessent)); + } + + /* This is not NTLM or NTLM with many bytes left to send: close + */ + conn->bits.close = TRUE; + k->size = 0; /* don't download any more than 0 bytes */ + } + + if(bytessent) + return Curl_readrewind(conn); + + return CURLE_OK; +} + +/* + * Curl_http_auth_act() gets called when a all HTTP headers have been received + * and it checks what authentication methods that are available and decides + * which one (if any) to use. It will set 'newurl' if an auth metod was + * picked. + */ + +CURLcode Curl_http_auth_act(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + bool pickhost = FALSE; + bool pickproxy = FALSE; + CURLcode code = CURLE_OK; + + if(100 == data->reqdata.keep.httpcode) + /* this is a transient response code, ignore */ + return CURLE_OK; + + if(data->state.authproblem) + return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; + + if(conn->bits.user_passwd && + ((data->reqdata.keep.httpcode == 401) || + (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) { + pickhost = pickoneauth(&data->state.authhost); + if(!pickhost) + data->state.authproblem = TRUE; + } + if(conn->bits.proxy_user_passwd && + ((data->reqdata.keep.httpcode == 407) || + (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) { + pickproxy = pickoneauth(&data->state.authproxy); + if(!pickproxy) + data->state.authproblem = TRUE; + } + + if(pickhost || pickproxy) { + data->reqdata.newurl = strdup(data->change.url); /* clone URL */ + + if((data->set.httpreq != HTTPREQ_GET) && + (data->set.httpreq != HTTPREQ_HEAD) && + !conn->bits.rewindaftersend) { + code = perhapsrewind(conn); + if(code) + return code; + } + } + + else if((data->reqdata.keep.httpcode < 300) && + (!data->state.authhost.done) && + conn->bits.authneg) { + /* no (known) authentication available, + authentication is not "done" yet and + no authentication seems to be required and + we didn't try HEAD or GET */ + if((data->set.httpreq != HTTPREQ_GET) && + (data->set.httpreq != HTTPREQ_HEAD)) { + data->reqdata.newurl = strdup(data->change.url); /* clone URL */ + data->state.authhost.done = TRUE; + } + } + if (Curl_http_should_fail(conn)) { + failf (data, "The requested URL returned error: %d", + data->reqdata.keep.httpcode); + code = CURLE_HTTP_RETURNED_ERROR; + } + + return code; +} + +/** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication + * method. conn->data->state.authdone is set to TRUE when authentication is + * done. + * + * @param conn all information about the current connection + * @param request pointer to the request keyword + * @param path pointer to the requested path + * @param proxytunnel boolean if this is the request setting up a "proxy + * tunnel" + * + * @returns CURLcode + */ +static CURLcode +Curl_http_output_auth(struct connectdata *conn, + char *request, + char *path, + bool proxytunnel) /* TRUE if this is the request setting + up the proxy tunnel */ +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *auth=NULL; + struct auth *authhost; + struct auth *authproxy; + + curlassert(data); + + authhost = &data->state.authhost; + authproxy = &data->state.authproxy; + + if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || + conn->bits.user_passwd) + /* continue please */ ; + else { + authhost->done = TRUE; + authproxy->done = TRUE; + return CURLE_OK; /* no authentication with no user or password */ + } + + 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'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'll be used instantly. */ + authproxy->picked = authproxy->want; + + /* Send proxy authentication header if needed */ + if (conn->bits.httpproxy && + (conn->bits.tunnel_proxy == proxytunnel)) { +#ifdef USE_NTLM + if(authproxy->picked == CURLAUTH_NTLM) { + auth=(char *)"NTLM"; + result = Curl_output_ntlm(conn, TRUE); + if(result) + return result; + } + else +#endif + if(authproxy->picked == CURLAUTH_BASIC) { + /* Basic */ + if(conn->bits.proxy_user_passwd && + !checkheaders(data, "Proxy-authorization:")) { + auth=(char *)"Basic"; + result = Curl_output_basic(conn, TRUE); + if(result) + return result; + } + /* NOTE: Curl_output_basic() should set 'done' TRUE, as the other auth + functions work that way */ + authproxy->done = TRUE; + } +#ifndef CURL_DISABLE_CRYPTO_AUTH + else if(authproxy->picked == CURLAUTH_DIGEST) { + auth=(char *)"Digest"; + result = Curl_output_digest(conn, + TRUE, /* proxy */ + (unsigned char *)request, + (unsigned char *)path); + if(result) + return result; + } +#endif + if(auth) { + infof(data, "Proxy auth using %s with user '%s'\n", + auth, conn->proxyuser?conn->proxyuser:""); + authproxy->multi = (bool)(!authproxy->done); + } + else + authproxy->multi = FALSE; + } + else + /* we have no proxy so let's pretend we're done authenticating + with it */ + authproxy->done = TRUE; + + /* To prevent the user+password to get sent to other than the original + host due to a location-follow, we do some weirdo checks here */ + if(!data->state.this_is_a_follow || + conn->bits.netrc || + !data->state.first_host || + curl_strequal(data->state.first_host, conn->host.name) || + data->set.http_disable_hostname_check_before_authentication) { + + /* Send web authentication header if needed */ + { + auth = NULL; +#ifdef HAVE_GSSAPI + if((authhost->picked == CURLAUTH_GSSNEGOTIATE) && + data->state.negotiate.context && + !GSS_ERROR(data->state.negotiate.status)) { + auth=(char *)"GSS-Negotiate"; + result = Curl_output_negotiate(conn); + if (result) + return result; + authhost->done = TRUE; + } + else +#endif +#ifdef USE_NTLM + if(authhost->picked == CURLAUTH_NTLM) { + auth=(char *)"NTLM"; + result = Curl_output_ntlm(conn, FALSE); + if(result) + return result; + } + else +#endif + { +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(authhost->picked == CURLAUTH_DIGEST) { + auth=(char *)"Digest"; + result = Curl_output_digest(conn, + FALSE, /* not a proxy */ + (unsigned char *)request, + (unsigned char *)path); + if(result) + return result; + } else +#endif + if(authhost->picked == CURLAUTH_BASIC) { + if(conn->bits.user_passwd && + !checkheaders(data, "Authorization:")) { + auth=(char *)"Basic"; + result = Curl_output_basic(conn, FALSE); + if(result) + return result; + } + /* basic is always ready */ + authhost->done = TRUE; + } + } + if(auth) { + infof(data, "Server auth using %s with user '%s'\n", + auth, conn->user); + + authhost->multi = (bool)(!authhost->done); + } + else + authhost->multi = FALSE; + } + } + else + authhost->done = TRUE; + + return result; +} + + +/* + * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: + * headers. They are dealt with both in the transfer.c main loop and in the + * proxy CONNECT loop. + */ + +CURLcode Curl_http_input_auth(struct connectdata *conn, + int httpcode, + char *header) /* the first non-space */ +{ + /* + * This resource requires authentication + */ + struct SessionHandle *data = conn->data; + + long *availp; + char *start; + struct auth *authp; + + if (httpcode == 407) { + start = header+strlen("Proxy-authenticate:"); + availp = &data->info.proxyauthavail; + authp = &data->state.authproxy; + } + else { + start = header+strlen("WWW-Authenticate:"); + availp = &data->info.httpauthavail; + authp = &data->state.authhost; + } + + /* pass all white spaces */ + while(*start && ISSPACE(*start)) + start++; + + /* + * Here we check if we want the specific single authentication (using ==) and + * if we do, we initiate usage of it. + * + * If the provided authentication is wanted as one out of several accepted + * types (using &), we OR this authentication type to the authavail + * variable. + */ + +#ifdef HAVE_GSSAPI + if (checkprefix("GSS-Negotiate", start) || + checkprefix("Negotiate", start)) { + *availp |= CURLAUTH_GSSNEGOTIATE; + authp->avail |= CURLAUTH_GSSNEGOTIATE; + if(authp->picked == CURLAUTH_GSSNEGOTIATE) { + /* if exactly this is wanted, go */ + int neg = Curl_input_negotiate(conn, start); + if (neg == 0) { + data->reqdata.newurl = strdup(data->change.url); + data->state.authproblem = (data->reqdata.newurl == NULL); + } + else { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + } + else +#endif +#ifdef USE_NTLM + /* NTLM support requires the SSL crypto libs */ + if(checkprefix("NTLM", start)) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + if(authp->picked == CURLAUTH_NTLM) { + /* NTLM authentication is picked and activated */ + CURLntlm ntlm = + Curl_input_ntlm(conn, (bool)(httpcode == 407), start); + + if(CURLNTLM_BAD != ntlm) + data->state.authproblem = FALSE; + else { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + } + else +#endif +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(checkprefix("Digest", start)) { + if((authp->avail & CURLAUTH_DIGEST) != 0) { + infof(data, "Ignoring duplicate digest auth header.\n"); + } + else { + CURLdigest dig; + *availp |= CURLAUTH_DIGEST; + authp->avail |= CURLAUTH_DIGEST; + + /* We call this function on input Digest headers even if Digest + * authentication isn't activated yet, as we need to store the + * incoming data from this header in case we are gonna use Digest. */ + dig = Curl_input_digest(conn, (bool)(httpcode == 407), start); + + if(CURLDIGEST_FINE != dig) { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + } + else +#endif + if(checkprefix("Basic", start)) { + *availp |= CURLAUTH_BASIC; + authp->avail |= CURLAUTH_BASIC; + if(authp->picked == CURLAUTH_BASIC) { + /* We asked for Basic authentication but got a 40X back + anyway, which basicly means our name+password isn't + valid. */ + authp->avail = CURLAUTH_NONE; + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + + return CURLE_OK; +} + +/** + * Curl_http_should_fail() determines whether an HTTP response has gotten us + * into an error state or not. + * + * @param conn all information about the current connection + * + * @retval 0 communications should continue + * + * @retval 1 communications should not continue + */ +int Curl_http_should_fail(struct connectdata *conn) +{ + struct SessionHandle *data; + struct Curl_transfer_keeper *k; + + curlassert(conn); + data = conn->data; + curlassert(data); + + /* + ** For readability + */ + k = &data->reqdata.keep; + + /* + ** If we haven't been asked to fail on error, + ** don't fail. + */ + if (!data->set.http_fail_on_error) + return 0; + + /* + ** Any code < 400 is never terminal. + */ + if (k->httpcode < 400) + return 0; + + if (data->reqdata.resume_from && + (data->set.httpreq==HTTPREQ_GET) && + (k->httpcode == 416)) { + /* "Requested Range Not Satisfiable", just proceed and + pretend this is no error */ + return 0; + } + + /* + ** Any code >= 400 that's not 401 or 407 is always + ** a terminal error + */ + if ((k->httpcode != 401) && + (k->httpcode != 407)) + return 1; + + /* + ** All we have left to deal with is 401 and 407 + */ + curlassert((k->httpcode == 401) || (k->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'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. + */ +#if 0 /* set to 1 when debugging this functionality */ + infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage); + infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant); + infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail); + infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode); + infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone); + infof(data,"%s: newurl = %s\n",__FUNCTION__,data->reqdata.newurl ? data->reqdata.newurl : "(null)"); + infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem); +#endif + + /* + ** Either we're not authenticating, or we're supposed to + ** be authenticating something else. This is an error. + */ + if((k->httpcode == 401) && !conn->bits.user_passwd) + return TRUE; + if((k->httpcode == 407) && !conn->bits.proxy_user_passwd) + return TRUE; + + return data->state.authproblem; +} + +/* + * 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 connectdata *conn = (struct connectdata *)userp; + struct HTTP *http = conn->data->reqdata.proto.http; + size_t fullsize = size * nitems; + + if(0 == http->postsize) + /* nothing to return */ + return 0; + + /* make sure that a HTTP request is never sent away chunked! */ + conn->bits.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST); + + 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; + conn->fread = http->backup.fread; + conn->fread_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; +} + +/* ------------------------------------------------------------------------- */ +/* + * The add_buffer series of functions are used to build one large memory chunk + * from repeated function invokes. Used so that the entire HTTP request can + * be sent in one go. + */ + +struct send_buffer { + char *buffer; + size_t size_max; + size_t size_used; +}; +typedef struct send_buffer send_buffer; + +static CURLcode add_custom_headers(struct connectdata *conn, + send_buffer *req_buffer); +static CURLcode + add_buffer(send_buffer *in, const void *inptr, size_t size); + +/* + * add_buffer_init() sets up and returns a fine buffer struct + */ +static +send_buffer *add_buffer_init(void) +{ + send_buffer *blonk; + blonk=(send_buffer *)malloc(sizeof(send_buffer)); + if(blonk) { + memset(blonk, 0, sizeof(send_buffer)); + return blonk; + } + return NULL; /* failed, go home */ +} + +/* + * add_buffer_send() sends a header buffer and frees all associated memory. + * Body data may be appended to the header data if desired. + * + * Returns CURLcode + */ +static +CURLcode add_buffer_send(send_buffer *in, + struct connectdata *conn, + long *bytes_written, /* add the number of sent + bytes to this counter */ + size_t included_body_bytes, /* how much of the buffer + contains body data (for log tracing) */ + int socketindex) + +{ + ssize_t amount; + CURLcode res; + char *ptr; + size_t size; + struct HTTP *http = conn->data->reqdata.proto.http; + size_t sendsize; + curl_socket_t sockfd; + + curlassert(socketindex <= SECONDARYSOCKET); + + sockfd = conn->sock[socketindex]; + + /* 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 = in->buffer; + size = in->size_used; + +#ifdef CURL_DOES_CONVERSIONS + if(size - included_body_bytes > 0) { + res = Curl_convert_to_network(conn->data, ptr, size - included_body_bytes); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(res != CURLE_OK) { + /* conversion failed, free memory and return to the caller */ + if(in->buffer) + free(in->buffer); + free(in); + return res; + } + } +#endif /* CURL_DOES_CONVERSIONS */ + + if(conn->protocol & PROT_HTTPS) { + /* We never send more than CURL_MAX_WRITE_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. + */ + + sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE: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. + */ + memcpy(conn->data->state.uploadbuffer, ptr, sendsize); + ptr = conn->data->state.uploadbuffer; + } + else + sendsize = size; + + res = Curl_write(conn, sockfd, ptr, sendsize, &amount); + + if(CURLE_OK == res) { + + if(conn->data->set.verbose) { + /* this data _may_ contain binary stuff */ + Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, + (size_t)(amount-included_body_bytes), conn); + if (included_body_bytes) + Curl_debug(conn->data, CURLINFO_DATA_OUT, + ptr+amount-included_body_bytes, + (size_t)included_body_bytes, conn); + } + + *bytes_written += amount; + + if(http) { + 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 = in->buffer + amount; + + /* backup the currently set pointers */ + http->backup.fread = conn->fread; + http->backup.fread_in = conn->fread_in; + http->backup.postdata = http->postdata; + http->backup.postsize = http->postsize; + + /* set the new pointers for the request-sending */ + conn->fread = (curl_read_callback)readmoredata; + conn->fread_in = (void *)conn; + http->postdata = ptr; + http->postsize = (curl_off_t)size; + + http->send_buffer = in; + 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; + else + conn->writechannel_inuse = FALSE; + } + } + if(in->buffer) + free(in->buffer); + free(in); + + return res; +} + + +/* + * add_bufferf() add the formatted input to the buffer. + */ +static +CURLcode add_bufferf(send_buffer *in, const char *fmt, ...) +{ + char *s; + va_list ap; + va_start(ap, fmt); + s = vaprintf(fmt, ap); /* this allocs a new string to append */ + va_end(ap); + + if(s) { + CURLcode result = add_buffer(in, s, strlen(s)); + free(s); + if(CURLE_OK == result) + return CURLE_OK; + } + /* If we failed, we cleanup the whole buffer and return error */ + if(in->buffer) + free(in->buffer); + free(in); + return CURLE_OUT_OF_MEMORY; +} + +/* + * add_buffer() appends a memory chunk to the existing buffer + */ +static +CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size) +{ + char *new_rb; + size_t new_size; + + if(!in->buffer || + ((in->size_used + size) > (in->size_max - 1))) { + new_size = (in->size_used+size)*2; + if(in->buffer) + /* we have a buffer, enlarge the existing one */ + new_rb = (char *)realloc(in->buffer, new_size); + else + /* create a new buffer */ + new_rb = (char *)malloc(new_size); + + if(!new_rb) + return CURLE_OUT_OF_MEMORY; + + in->buffer = new_rb; + in->size_max = new_size; + } + memcpy(&in->buffer[in->size_used], inptr, size); + + in->size_used += size; + + return CURLE_OK; +} + +/* end of the add_buffer functions */ +/* ------------------------------------------------------------------------- */ + +/* + * Curl_compareheader() + * + * Returns TRUE if 'headerline' contains the 'header' with given 'content'. + * Pass headers WITH the colon. + */ +bool +Curl_compareheader(char *headerline, /* line to check */ + const char *header, /* header keyword _with_ colon */ + const char *content) /* content string to find */ +{ + /* RFC2616, section 4.2 says: "Each header field consists of a name followed + * by a colon (":") and the field value. Field names are case-insensitive. + * The field value MAY be preceded by any amount of LWS, though a single SP + * is preferred." */ + + size_t hlen = strlen(header); + size_t clen; + size_t len; + char *start; + char *end; + + if(!strnequal(headerline, header, hlen)) + return FALSE; /* doesn't start with header */ + + /* pass the header */ + start = &headerline[hlen]; + + /* pass all white spaces */ + while(*start && ISSPACE(*start)) + start++; + + /* find the end of the header line */ + end = strchr(start, '\r'); /* lines end with CRLF */ + if(!end) { + /* in case there's a non-standard compliant line here */ + end = strchr(start, '\n'); + + if(!end) + /* hm, there's no line ending here, use the zero byte! */ + end = strchr(start, '\0'); + } + + len = end-start; /* length of the content part of the input line */ + clen = strlen(content); /* length of the word to find */ + + /* find the content string in the rest of the line */ + for(;len>=clen;len--, start++) { + if(strnequal(start, content, clen)) + return TRUE; /* match! */ + } + + return FALSE; /* no match */ +} + +/* + * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This + * function will issue the necessary commands to get a seamless tunnel through + * this proxy. After that, the socket can be used just as a normal socket. + * + * This badly needs to be rewritten. CONNECT should be sent and dealt with + * like any ordinary HTTP request, and not specially crafted like this. This + * function only remains here like this for now since the rewrite is a bit too + * much work to do at the moment. + * + * This function is BLOCKING which is nasty for all multi interface using apps. + */ + +CURLcode Curl_proxyCONNECT(struct connectdata *conn, + int sockindex, + char *hostname, + int remote_port) +{ + int subversion=0; + struct SessionHandle *data=conn->data; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + CURLcode result; + int res; + size_t nread; /* total size read */ + int perline; /* count bytes per line */ + int keepon=TRUE; + ssize_t gotbytes; + char *ptr; + long timeout = + data->set.timeout?data->set.timeout:3600; /* in seconds */ + char *line_start; + char *host_port; + curl_socket_t tunnelsocket = conn->sock[sockindex]; + send_buffer *req_buffer; + curl_off_t cl=0; + bool closeConnection = FALSE; + +#define SELECT_OK 0 +#define SELECT_ERROR 1 +#define SELECT_TIMEOUT 2 + int error = SELECT_OK; + + infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); + conn->bits.proxy_connect_closed = FALSE; + + do { + if(data->reqdata.newurl) { + /* 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. */ + free(data->reqdata.newurl); + data->reqdata.newurl = NULL; + } + + /* initialize a dynamic send-buffer */ + req_buffer = add_buffer_init(); + + if(!req_buffer) + return CURLE_OUT_OF_MEMORY; + + host_port = aprintf("%s:%d", hostname, remote_port); + if(!host_port) + return CURLE_OUT_OF_MEMORY; + + /* Setup the proxy-authorization header, if any */ + result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE); + + if(CURLE_OK == result) { + char *host=(char *)""; + const char *proxyconn=""; + const char *useragent=""; + + if(!checkheaders(data, "Host:")) { + host = aprintf("Host: %s\r\n", host_port); + if(!host) + result = CURLE_OUT_OF_MEMORY; + } + if(!checkheaders(data, "Proxy-Connection:")) + proxyconn = "Proxy-Connection: Keep-Alive\r\n"; + + if(!checkheaders(data, "User-Agent:") && data->set.useragent) + useragent = conn->allocptr.uagent; + + if(CURLE_OK == result) { + /* Send the connect request to the proxy */ + /* BLOCKING */ + result = + add_bufferf(req_buffer, + "CONNECT %s:%d HTTP/1.0\r\n" + "%s" /* Host: */ + "%s" /* Proxy-Authorization */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ + hostname, remote_port, + host, + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + useragent, + proxyconn); + + if(CURLE_OK == result) + result = add_custom_headers(conn, req_buffer); + + if(host && *host) + free(host); + + if(CURLE_OK == result) + /* CRLF terminate the request */ + result = add_bufferf(req_buffer, "\r\n"); + + if(CURLE_OK == result) + /* Now send off the request */ + result = add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, sockindex); + } + if(result) + failf(data, "Failed sending CONNECT to proxy"); + } + free(host_port); + if(result) + return result; + + ptr=data->state.buffer; + line_start = ptr; + + nread=0; + perline=0; + keepon=TRUE; + + while((nreadnow)/1000; /* spent time */ + if(check <=0 ) { + failf(data, "Proxy CONNECT aborted due to timeout"); + error = SELECT_TIMEOUT; /* already too little time */ + break; + } + + /* timeout each second and check the timeout */ + switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD, 1000)) { + case -1: /* select() error, stop reading */ + error = SELECT_ERROR; + failf(data, "Proxy CONNECT aborted due to select() error"); + break; + case 0: /* timeout */ + break; + default: + res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); + if(res< 0) + /* EWOULDBLOCK */ + continue; /* go loop yourself */ + else if(res) + keepon = FALSE; + else if(gotbytes <= 0) { + keepon = FALSE; + error = SELECT_ERROR; + failf(data, "Proxy CONNECT aborted"); + } + else { + /* + * We got a whole chunk of data, which can be anything from one byte + * to a set of lines and possibly just a piece of the last line. + */ + int i; + + nread += gotbytes; + + if(keepon > TRUE) { + /* This means we are currently ignoring a response-body, so we + simply count down our counter and make sure to break out of the + loop when we're done! */ + cl -= gotbytes; + if(cl<=0) { + keepon = FALSE; + break; + } + } + else + for(i = 0; i < gotbytes; ptr++, i++) { + perline++; /* amount of bytes in this line so far */ + if(*ptr=='\n') { + char letter; + int writetype; + + /* output debug if that is requested */ + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, + line_start, (size_t)perline, conn); + + /* send the header to the callback */ + writetype = CLIENTWRITE_HEADER; + if(data->set.include_header) + writetype |= CLIENTWRITE_BODY; + + result = Curl_client_write(conn, writetype, line_start, perline); + if(result) + return result; + + /* 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.*/ + + if(('\r' == line_start[0]) || + ('\n' == line_start[0])) { + /* end of response-headers from the proxy */ + if(cl && (407 == k->httpcode) && !data->state.authproblem) { + /* If we get a 407 response code with content length when we + * have no auth problem, we must ignore the whole + * response-body */ + keepon = 2; + infof(data, "Ignore %" FORMAT_OFF_T + " bytes of response-body\n", cl); + cl -= (gotbytes - i);/* remove the remaining chunk of what + we already read */ + if(cl<=0) + /* if the whole thing was already read, we are done! */ + keepon=FALSE; + } + else + keepon = FALSE; + break; /* breaks out of for-loop, not switch() */ + } + + /* keep a backup of the position we are about to blank */ + letter = line_start[perline]; + line_start[perline]=0; /* zero terminate the buffer */ + if((checkprefix("WWW-Authenticate:", line_start) && + (401 == k->httpcode)) || + (checkprefix("Proxy-authenticate:", line_start) && + (407 == k->httpcode))) { + result = Curl_http_input_auth(conn, k->httpcode, line_start); + if(result) + return result; + } + else if(checkprefix("Content-Length:", line_start)) { + cl = curlx_strtoofft(line_start + strlen("Content-Length:"), + NULL, 10); + } + else if(Curl_compareheader(line_start, + "Connection:", "close")) + closeConnection = TRUE; + else if(2 == sscanf(line_start, "HTTP/1.%d %d", + &subversion, + &k->httpcode)) { + /* store the HTTP code from the proxy */ + data->info.httpproxycode = k->httpcode; + } + /* put back the letter we blanked out before */ + line_start[perline]= letter; + + perline=0; /* line starts over here */ + line_start = ptr+1; /* this skips the zero byte we wrote */ + } + } + } + break; + } /* switch */ + } /* while there's buffer left and loop is requested */ + + if(error) + return CURLE_RECV_ERROR; + + if(data->info.httpproxycode != 200) + /* Deal with the possibly already received authenticate + headers. 'newurl' is set to a new URL if we must loop. */ + Curl_http_auth_act(conn); + + if (closeConnection && data->reqdata.newurl) { + /* Connection closed by server. Don't use it anymore */ + sclose(conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + break; + } + } while(data->reqdata.newurl); + + if(200 != k->httpcode) { + failf(data, "Received HTTP code %d from proxy after CONNECT", + k->httpcode); + + if (closeConnection && data->reqdata.newurl) + conn->bits.proxy_connect_closed = TRUE; + + return CURLE_RECV_ERROR; + } + + /* If a proxy-authorization header was used for the proxy, then we should + 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(conn->allocptr.proxyuserpwd); + conn->allocptr.proxyuserpwd = NULL; + + data->state.authproxy.done = TRUE; + + infof (data, "Proxy replied OK to CONNECT request\n"); + return CURLE_OK; +} + +/* + * Curl_http_connect() performs HTTP stuff to do at connect-time, called from + * the generic Curl_connect(). + */ +CURLcode Curl_http_connect(struct connectdata *conn, bool *done) +{ + struct SessionHandle *data; + CURLcode result; + + data=conn->data; + + /* If we are not using a proxy and we want a secure connection, perform SSL + * initialization & connection now. If using a proxy with https, then we + * must tell the proxy to CONNECT to the host we want to talk to. Only + * after the connect has occurred, can we start talking SSL + */ + + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { + + /* either SSL over proxy, or explicitly asked for */ + result = Curl_proxyCONNECT(conn, FIRSTSOCKET, + conn->host.name, + conn->remote_port); + if(CURLE_OK != result) + return result; + } + + if(!data->state.this_is_a_follow) { + /* this is not a followed location, get the original host name */ + if (data->state.first_host) + /* Free to avoid leaking memory on multiple requests*/ + free(data->state.first_host); + + data->state.first_host = strdup(conn->host.name); + if(!data->state.first_host) + return CURLE_OUT_OF_MEMORY; + } + + if(conn->protocol & PROT_HTTPS) { + /* perform SSL initialization */ + if(data->state.used_interface == Curl_if_multi) { + result = Curl_https_connecting(conn, done); + if(result) + return result; + } + else { + /* BLOCKING */ + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(result) + return result; + *done = TRUE; + } + } + else { + *done = TRUE; + } + + return CURLE_OK; +} + +CURLcode Curl_https_connecting(struct connectdata *conn, bool *done) +{ + CURLcode result; + curlassert(conn->protocol & PROT_HTTPS); + + /* perform SSL initialization for this socket */ + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done); + if(result) + return result; + + return CURLE_OK; +} + +#ifdef USE_SSLEAY +/* This function is OpenSSL-specific. It should be made to query the generic + SSL layer instead. */ +int Curl_https_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + if (conn->protocol & PROT_HTTPS) { + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + + if(!numsocks) + return GETSOCK_BLANK; + + if (connssl->connecting_state == ssl_connect_2_writing) { + /* write mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_WRITESOCK(0); + } + else if (connssl->connecting_state == ssl_connect_2_reading) { + /* read mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); + } + } + return CURLE_OK; +} +#else +#ifdef USE_GNUTLS +int Curl_https_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + (void)conn; + (void)socks; + (void)numsocks; + return GETSOCK_BLANK; +} +#endif +#endif + +/* + * Curl_http_done() gets called from Curl_done() after a single HTTP request + * has been performed. + */ + +CURLcode Curl_http_done(struct connectdata *conn, + CURLcode status, bool premature) +{ + struct SessionHandle *data = conn->data; + struct HTTP *http =data->reqdata.proto.http; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + (void)premature; /* not used */ + + /* set the proper values (possibly modified on POST) */ + conn->fread = data->set.fread; /* restore */ + conn->fread_in = data->set.in; /* restore */ + + if (http == NULL) + return CURLE_OK; + + if(http->send_buffer) { + send_buffer *buff = http->send_buffer; + + free(buff->buffer); + free(buff); + http->send_buffer = NULL; /* clear the pointer */ + } + + if(HTTPREQ_POST_FORM == data->set.httpreq) { + k->bytecount = http->readbytecount + http->writebytecount; + + Curl_formclean(&http->sendit); /* Now free that whole lot */ + if(http->form.fp) { + /* a file being uploaded was left opened, close it! */ + fclose(http->form.fp); + http->form.fp = NULL; + } + } + else if(HTTPREQ_PUT == data->set.httpreq) + k->bytecount = http->readbytecount + http->writebytecount; + + if (status != CURLE_OK) + return (status); + + if(!conn->bits.retry && + ((http->readbytecount + + conn->headerbytecount - + conn->deductheadercount)) <= 0) { + /* 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"); + return CURLE_GOT_NOTHING; + } + + return CURLE_OK; +} + +/* check and possibly add an Expect: header */ +static CURLcode expect100(struct SessionHandle *data, + send_buffer *req_buffer) +{ + CURLcode result = CURLE_OK; + data->state.expect100header = FALSE; /* default to false unless it is set + to TRUE below */ + if((data->set.httpversion != CURL_HTTP_VERSION_1_0) && + !checkheaders(data, "Expect:")) { + /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect: + 100-continue to the headers which actually speeds up post + operations (as there is one packet coming back from the web + server) */ + result = add_bufferf(req_buffer, + "Expect: 100-continue\r\n"); + if(result == CURLE_OK) + data->state.expect100header = TRUE; + } + return result; +} + +static CURLcode add_custom_headers(struct connectdata *conn, + send_buffer *req_buffer) +{ + CURLcode result = CURLE_OK; + char *ptr; + struct curl_slist *headers=conn->data->set.headers; + + while(headers) { + ptr = strchr(headers->data, ':'); + if(ptr) { + /* we require a colon for this to be a true header */ + + ptr++; /* pass the colon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* only send this if the contents was non-blank */ + + if(conn->allocptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + curl_strnequal("Host:", headers->data, 5)) + ; + else if(conn->data->set.httpreq == HTTPREQ_POST_FORM && + /* this header (extended by formdata.c) is sent later */ + curl_strnequal("Content-Type:", headers->data, + strlen("Content-Type:"))) + ; + else { + result = add_bufferf(req_buffer, "%s\r\n", headers->data); + if(result) + return result; + } + } + } + headers = headers->next; + } + return result; +} + +/* + * Curl_http() gets called from the generic Curl_do() function when a HTTP + * request is to be performed. This creates and sends a properly constructed + * HTTP request. + */ +CURLcode Curl_http(struct connectdata *conn, bool *done) +{ + struct SessionHandle *data=conn->data; + char *buf = data->state.buffer; /* this is a short cut to the buffer */ + CURLcode result=CURLE_OK; + struct HTTP *http; + char *ppath = data->reqdata.path; + char *host = conn->host.name; + const char *te = ""; /* transfer-encoding */ + char *ptr; + char *request; + Curl_HttpReq httpreq = data->set.httpreq; + char *addcookies = NULL; + curl_off_t included_body = 0; + + /* Always consider the DO phase done after this function call, even if there + 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; + + if(!data->reqdata.proto.http) { + /* Only allocate this struct if we don't already have it! */ + + http = (struct HTTP *)malloc(sizeof(struct HTTP)); + if(!http) + return CURLE_OUT_OF_MEMORY; + memset(http, 0, sizeof(struct HTTP)); + data->reqdata.proto.http = http; + } + else + http = data->reqdata.proto.http; + + /* We default to persistent connections */ + conn->bits.close = FALSE; + + if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) && + data->set.upload) { + httpreq = HTTPREQ_PUT; + } + + /* Now set the 'request' pointer to the proper request string */ + if(data->set.customrequest) + request = data->set.customrequest; + else { + if(conn->bits.no_body) + request = (char *)"HEAD"; + else { + curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST)); + switch(httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + request = (char *)"POST"; + break; + case HTTPREQ_PUT: + request = (char *)"PUT"; + break; + default: /* this should never happen */ + case HTTPREQ_GET: + request = (char *)"GET"; + break; + case HTTPREQ_HEAD: + request = (char *)"HEAD"; + break; + } + } + } + + /* The User-Agent string might have been allocated in url.c already, because + it might have been used in the proxy connect, but if we have got a header + with the user-agent string specified, we erase the previously made string + here. */ + if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) { + free(conn->allocptr.uagent); + conn->allocptr.uagent=NULL; + } + + /* setup the authentication headers */ + result = Curl_http_output_auth(conn, request, ppath, FALSE); + if(result) + return result; + + if((data->state.authhost.multi || data->state.authproxy.multi) && + (httpreq != HTTPREQ_GET) && + (httpreq != HTTPREQ_HEAD)) { + /* Auth is required and we are not authenticated yet. Make a PUT or POST + with content-length zero as a "probe". */ + conn->bits.authneg = TRUE; + } + else + conn->bits.authneg = FALSE; + + Curl_safefree(conn->allocptr.ref); + if(data->change.referer && !checkheaders(data, "Referer:")) + conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); + else + conn->allocptr.ref = NULL; + + if(data->set.cookie && !checkheaders(data, "Cookie:")) + addcookies = data->set.cookie; + + if(!checkheaders(data, "Accept-Encoding:") && + data->set.encoding) { + Curl_safefree(conn->allocptr.accept_encoding); + conn->allocptr.accept_encoding = + aprintf("Accept-Encoding: %s\r\n", data->set.encoding); + if(!conn->allocptr.accept_encoding) + return CURLE_OUT_OF_MEMORY; + } + + ptr = checkheaders(data, "Transfer-Encoding:"); + if(ptr) { + /* Some kind of TE is requested, check if 'chunked' is chosen */ + conn->bits.upload_chunky = + Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); + } + else { + if (httpreq == HTTPREQ_GET) + conn->bits.upload_chunky = FALSE; + if(conn->bits.upload_chunky) + te = "Transfer-Encoding: chunked\r\n"; + } + + Curl_safefree(conn->allocptr.host); + + ptr = checkheaders(data, "Host:"); + if(ptr && (!data->state.this_is_a_follow || + curl_strequal(data->state.first_host, conn->host.name))) { +#if !defined(CURL_DISABLE_COOKIES) + /* 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 host name + is the same as the first one! */ + char *start = ptr+strlen("Host:"); + while(*start && ISSPACE(*start )) + start++; + ptr = start; /* start host-scanning here */ + + /* scan through the string to find the end (space or colon) */ + while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr)) + ptr++; + + if(ptr != start) { + size_t len=ptr-start; + Curl_safefree(conn->allocptr.cookiehost); + conn->allocptr.cookiehost = malloc(len+1); + if(!conn->allocptr.cookiehost) + return CURLE_OUT_OF_MEMORY; + memcpy(conn->allocptr.cookiehost, start, len); + conn->allocptr.cookiehost[len]=0; + } +#endif + + conn->allocptr.host = NULL; + } + else { + /* When building Host: headers, we must put the host name within + [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ + + if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) || + (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) ) + /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include + the port number in the host string */ + conn->allocptr.host = aprintf("Host: %s%s%s\r\n", + conn->bits.ipv6_ip?"[":"", + host, + conn->bits.ipv6_ip?"]":""); + else + conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n", + conn->bits.ipv6_ip?"[":"", + host, + conn->bits.ipv6_ip?"]":"", + conn->remote_port); + + if(!conn->allocptr.host) + /* without Host: we can't make a nice request */ + return CURLE_OUT_OF_MEMORY; + } + + if (conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + /* Using a proxy but does not tunnel through it */ + + /* 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 host name! */ + if(conn->host.dispname != conn->host.name) { + char *url = data->change.url; + ptr = strstr(url, conn->host.dispname); + if(ptr) { + /* This is where the display name starts in the URL, now replace this + part with the encoded name. TODO: This method of replacing the host + name is rather crude as I believe there's a slight risk that the + user has entered a user name or password that contain the host name + string. */ + size_t currlen = strlen(conn->host.dispname); + size_t newlen = strlen(conn->host.name); + size_t urllen = strlen(url); + + char *newurl; + + newurl = malloc(urllen + newlen - currlen + 1); + if(newurl) { + /* copy the part before the host name */ + memcpy(newurl, url, ptr - url); + /* append the new host name instead of the old */ + memcpy(newurl + (ptr - url), conn->host.name, newlen); + /* append the piece after the host name */ + memcpy(newurl + newlen + (ptr - url), + ptr + currlen, /* copy the trailing zero byte too */ + urllen - (ptr-url) - currlen + 1); + if(data->change.url_alloc) + free(data->change.url); + data->change.url = newurl; + data->change.url_alloc = TRUE; + } + else + return CURLE_OUT_OF_MEMORY; + } + } + ppath = data->change.url; + } + if(HTTPREQ_POST_FORM == httpreq) { + /* we must build the whole darned post sequence first, so that we have + a size of the whole shebang before we start to send it */ + result = Curl_getFormData(&http->sendit, data->set.httppost, + checkheaders(data, "Content-Type:"), + &http->postsize); + if(CURLE_OK != result) { + /* Curl_getFormData() doesn't use failf() */ + failf(data, "failed creating formpost data"); + return result; + } + } + + + http->p_pragma = + (!checkheaders(data, "Pragma:") && + (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )? + "Pragma: no-cache\r\n":NULL; + + if(!checkheaders(data, "Accept:")) + http->p_accept = "Accept: */*\r\n"; + + if(( (HTTPREQ_POST == httpreq) || + (HTTPREQ_POST_FORM == httpreq) || + (HTTPREQ_PUT == httpreq) ) && + data->reqdata.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. + *********************************************************************/ + + if(data->reqdata.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->reqdata.resume_from = 0; + } + + if(data->reqdata.resume_from) { + /* do we still game? */ + curl_off_t passed=0; + + /* Now, let's read off the proper amount of bytes from the + input. If we knew it was a proper file we could've just + fseek()ed but we only have a stream here */ + do { + size_t readthisamountnow = (size_t)(data->reqdata.resume_from - passed); + size_t actuallyread; + + if(readthisamountnow > BUFSIZE) + readthisamountnow = BUFSIZE; + + actuallyread = + data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow, + data->set.in); + + passed += actuallyread; + if(actuallyread != readthisamountnow) { + failf(data, "Could only read %" FORMAT_OFF_T + " bytes from the input", + passed); + return CURLE_READ_ERROR; + } + } while(passed != data->reqdata.resume_from); /* loop until done */ + + /* now, decrease the size of the read */ + if(data->set.infilesize>0) { + data->set.infilesize -= data->reqdata.resume_from; + + if(data->set.infilesize <= 0) { + failf(data, "File already completely uploaded"); + return CURLE_PARTIAL_FILE; + } + } + /* we've passed, proceed as normal */ + } + } + if(data->reqdata.use_range) { + /* + * 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. + */ + if((httpreq == HTTPREQ_GET) && + !checkheaders(data, "Range:")) { + /* if a line like this was already allocated, free the previous one */ + if(conn->allocptr.rangeline) + free(conn->allocptr.rangeline); + conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->reqdata.range); + } + else if((httpreq != HTTPREQ_GET) && + !checkheaders(data, "Content-Range:")) { + + if(data->reqdata.resume_from) { + /* This is because "resume" was selected */ + curl_off_t total_expected_size= + data->reqdata.resume_from + data->set.infilesize; + conn->allocptr.rangeline = + aprintf("Content-Range: bytes %s%" FORMAT_OFF_T + "/%" FORMAT_OFF_T "\r\n", + data->reqdata.range, total_expected_size-1, + total_expected_size); + } + else { + /* Range was selected and then we just pass the incoming range and + append total size */ + conn->allocptr.rangeline = + aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", + data->reqdata.range, data->set.infilesize); + } + } + } + + { + /* Use 1.1 unless the use specificly asked for 1.0 */ + const char *httpstring= + data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1"; + + send_buffer *req_buffer; + curl_off_t postsize; /* off_t type to be able to hold a large file size */ + + /* initialize a dynamic send-buffer */ + req_buffer = add_buffer_init(); + + if(!req_buffer) + return CURLE_OUT_OF_MEMORY; + + /* add the main request stuff */ + result = + add_bufferf(req_buffer, + "%s " /* GET/HEAD/POST/PUT */ + "%s HTTP/%s\r\n" /* path + HTTP version */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* host */ + "%s" /* pragma */ + "%s" /* accept */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s" /* Proxy-Connection */ + "%s",/* transfer-encoding */ + + request, + ppath, + httpstring, + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + conn->allocptr.userpwd?conn->allocptr.userpwd:"", + (data->reqdata.use_range && conn->allocptr.rangeline)? + conn->allocptr.rangeline:"", + (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)? + conn->allocptr.uagent:"", + (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ + http->p_pragma?http->p_pragma:"", + http->p_accept?http->p_accept:"", + (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !checkheaders(data, "Proxy-Connection:"))? + "Proxy-Connection: Keep-Alive\r\n":"", + te + ); + + if(result) + return result; + +#if !defined(CURL_DISABLE_COOKIES) + if(data->cookies || addcookies) { + struct Cookie *co=NULL; /* no cookies from start */ + int count=0; + + if(data->cookies) { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + co = Curl_cookie_getlist(data->cookies, + conn->allocptr.cookiehost? + conn->allocptr.cookiehost:host, data->reqdata.path, + (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE)); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + if(co) { + struct Cookie *store=co; + /* now loop through all cookies that matched */ + while(co) { + if(co->value) { + if(0 == count) { + result = add_bufferf(req_buffer, "Cookie: "); + if(result) + break; + } + result = add_bufferf(req_buffer, + "%s%s=%s", count?"; ":"", + co->name, co->value); + if(result) + break; + count++; + } + co = co->next; /* next cookie please */ + } + Curl_cookie_freelist(store); /* free the cookie list */ + } + if(addcookies && (CURLE_OK == result)) { + if(!count) + result = add_bufferf(req_buffer, "Cookie: "); + if(CURLE_OK == result) { + result = add_bufferf(req_buffer, "%s%s", + count?"; ":"", + addcookies); + count++; + } + } + if(count && (CURLE_OK == result)) + result = add_buffer(req_buffer, "\r\n", 2); + + if(result) + return result; + } +#endif + + if(data->set.timecondition) { + struct tm *tm; + + /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since + * header family should have their times set in GMT as RFC2616 defines: + * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time + * (GMT), without exception. For the purposes of HTTP, GMT is exactly + * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616). + */ + +#ifdef HAVE_GMTIME_R + /* thread-safe version */ + struct tm keeptime; + tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime); +#else + tm = gmtime(&data->set.timevalue); +#endif + + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + snprintf(buf, BUFSIZE-1, + "%s, %02d %s %4d %02d:%02d:%02d GMT", + 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); + + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + result = add_bufferf(req_buffer, + "If-Modified-Since: %s\r\n", buf); + break; + case CURL_TIMECOND_IFUNMODSINCE: + result = add_bufferf(req_buffer, + "If-Unmodified-Since: %s\r\n", buf); + break; + case CURL_TIMECOND_LASTMOD: + result = add_bufferf(req_buffer, + "Last-Modified: %s\r\n", buf); + break; + } + if(result) + return result; + } + + result = add_custom_headers(conn, req_buffer); + if(result) + return result; + + http->postdata = NULL; /* nothing to post at this point */ + Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */ + + /* If 'authdone' is FALSE, we must not set the write socket index to the + Curl_transfer() call below, as we're not ready to actually upload any + data yet. */ + + switch(httpreq) { + + case HTTPREQ_POST_FORM: + if(!http->sendit || conn->bits.authneg) { + /* nothing to post! */ + result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n"); + if(result) + return result; + + result = add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); + if(result) + failf(data, "Failed sending POST request"); + else + /* setup variables for the upcoming transfer */ + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, + &http->readbytecount, + -1, NULL); + break; + } + + if(Curl_FormInit(&http->form, http->sendit)) { + failf(data, "Internal HTTP POST error!"); + return CURLE_HTTP_POST_ERROR; + } + + /* set the read function to read from the generated form data */ + conn->fread = (curl_read_callback)Curl_FormReader; + conn->fread_in = &http->form; + + http->sending = HTTPSEND_BODY; + + if(!conn->bits.upload_chunky) { + /* only add Content-Length if not uploading chunked */ + result = add_bufferf(req_buffer, + "Content-Length: %" FORMAT_OFF_T "\r\n", + http->postsize); + if(result) + return result; + } + + result = expect100(data, req_buffer); + if(result) + return result; + + { + + /* Get Content-Type: line from Curl_formpostheader. + */ + char *contentType; + size_t linelength=0; + contentType = Curl_formpostheader((void *)&http->form, + &linelength); + if(!contentType) { + failf(data, "Could not get Content-Type header line!"); + return CURLE_HTTP_POST_ERROR; + } + + result = add_buffer(req_buffer, contentType, linelength); + if(result) + return result; + } + + /* make the request end in a true CRLF */ + result = add_buffer(req_buffer, "\r\n", 2); + if(result) + return result; + + /* set upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, http->postsize); + + /* fire away the whole request to the server */ + result = add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); + if(result) + failf(data, "Failed sending POST request"); + else + /* setup variables for the upcoming transfer */ + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, + &http->readbytecount, + FIRSTSOCKET, + &http->writebytecount); + + if(result) { + Curl_formclean(&http->sendit); /* free that whole lot */ + return result; + } +#ifdef CURL_DOES_CONVERSIONS +/* time to convert the form data... */ + result = Curl_formconvert(data, http->sendit); + if(result) { + Curl_formclean(&http->sendit); /* free that whole lot */ + return result; + } +#endif /* CURL_DOES_CONVERSIONS */ + break; + + case HTTPREQ_PUT: /* Let's PUT the data to the server! */ + + if(conn->bits.authneg) + postsize = 0; + else + postsize = data->set.infilesize; + + if((postsize != -1) && !conn->bits.upload_chunky) { + /* only add Content-Length if not uploading chunked */ + result = add_bufferf(req_buffer, + "Content-Length: %" FORMAT_OFF_T "\r\n", + postsize ); + if(result) + return result; + } + + result = expect100(data, req_buffer); + if(result) + return result; + + result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */ + if(result) + return result; + + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, postsize); + + /* this sends the buffer and frees all the buffer resources */ + result = add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); + if(result) + failf(data, "Failed sending PUT request"); + else + /* prepare for transfer */ + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, + &http->readbytecount, + postsize?FIRSTSOCKET:-1, + postsize?&http->writebytecount:NULL); + if(result) + return result; + break; + + case HTTPREQ_POST: + /* this is the simple POST, using x-www-form-urlencoded style */ + + if(conn->bits.authneg) + postsize = 0; + else + /* figure out the size of the postfields */ + postsize = (data->set.postfieldsize != -1)? + data->set.postfieldsize: + (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0); + + if(!conn->bits.upload_chunky) { + /* 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(!checkheaders(data, "Content-Length:")) { + /* we allow replacing this header, although it isn't very wise to + actually set your own */ + result = add_bufferf(req_buffer, + "Content-Length: %" FORMAT_OFF_T"\r\n", + postsize); + if(result) + return result; + } + } + + if(!checkheaders(data, "Content-Type:")) { + result = add_bufferf(req_buffer, + "Content-Type: application/x-www-form-urlencoded\r\n"); + if(result) + return result; + } + + if(data->set.postfields) { + + /* for really small posts we don't use Expect: headers at all, and for + the somewhat bigger ones we allow the app to disable it */ + if(postsize > TINY_INITIAL_POST_SIZE) { + result = expect100(data, req_buffer); + if(result) + return result; + } + else + data->state.expect100header = FALSE; + + if(!data->state.expect100header && + (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. */ + + result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ + if(result) + return result; + + if(!conn->bits.upload_chunky) { + /* We're not sending it 'chunked', append it to the request + already now to reduce the number if send() calls */ + result = add_buffer(req_buffer, data->set.postfields, + (size_t)postsize); + included_body = postsize; + } + else { + /* Append the POST data chunky-style */ + result = add_bufferf(req_buffer, "%x\r\n", (int)postsize); + if(CURLE_OK == result) + result = add_buffer(req_buffer, data->set.postfields, + (size_t)postsize); + if(CURLE_OK == result) + result = add_buffer(req_buffer, + "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); + /* CR LF 0 CR LF CR LF */ + included_body = postsize + 7; + } + if(result) + return result; + } + else { + /* A huge POST coming up, do data separate from the request */ + http->postsize = postsize; + http->postdata = data->set.postfields; + + http->sending = HTTPSEND_BODY; + + conn->fread = (curl_read_callback)readmoredata; + conn->fread_in = (void *)conn; + + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, http->postsize); + + add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ + } + } + else { + add_buffer(req_buffer, "\r\n", 2); /* end of headers! */ + + if(data->set.postfieldsize) { + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, postsize?postsize:-1); + + /* set the pointer to mark that we will send the post body using + the read callback */ + http->postdata = (char *)&http->postdata; + } + } + /* issue the request */ + result = add_buffer_send(req_buffer, conn, &data->info.request_size, + (size_t)included_body, FIRSTSOCKET); + + if(result) + failf(data, "Failed sending HTTP POST request"); + else + result = + Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, + &http->readbytecount, + http->postdata?FIRSTSOCKET:-1, + http->postdata?&http->writebytecount:NULL); + break; + + default: + add_buffer(req_buffer, "\r\n", 2); + + /* issue the request */ + result = add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); + + if(result) + failf(data, "Failed sending HTTP request"); + else + /* HTTP GET/HEAD download: */ + result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, + &http->readbytecount, + http->postdata?FIRSTSOCKET:-1, + http->postdata?&http->writebytecount:NULL); + } + if(result) + return result; + } + + return CURLE_OK; +} +#endif diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h new file mode 100644 index 0000000..0f4b58f --- /dev/null +++ b/Utilities/cmcurl/lib/http.h @@ -0,0 +1,85 @@ +#ifndef __HTTP_H +#define __HTTP_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_HTTP +bool Curl_compareheader(char *headerline, /* line to check */ + const char *header, /* header keyword _with_ colon */ + const char *content); /* content string to find */ + +/* ftp can use this as well */ +CURLcode Curl_proxyCONNECT(struct connectdata *conn, + int tunnelsocket, + char *hostname, int remote_port); + +/* protocol-specific functions set up to be called by the main engine */ +CURLcode Curl_http(struct connectdata *conn, bool *done); +CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); +CURLcode Curl_http_connect(struct connectdata *conn, bool *done); +CURLcode Curl_https_connecting(struct connectdata *conn, bool *done); +int Curl_https_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + +/* The following functions are defined in http_chunks.c */ +void Curl_httpchunk_init(struct connectdata *conn); +CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, + ssize_t length, ssize_t *wrote); + +/* These functions are in http.c */ +void Curl_http_auth_stage(struct SessionHandle *data, int stage); +CURLcode Curl_http_input_auth(struct connectdata *conn, + int httpcode, char *header); +CURLcode Curl_http_auth_act(struct connectdata *conn); + +int Curl_http_should_fail(struct connectdata *conn); + +/* If only the PICKNONE bit is set, there has been a round-trip and we + 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) /* 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 + data is larger than this, it will automatically get split up in multiple + system calls. + + This value used to be fairly big (100K), but we must take into account that + if the server rejects the POST due for authentication reasons, this data + will always be uncondtionally sent and thus it may not be larger than can + always be afforded to send twice. + + It must not be greater than 64K to work on VMS. +*/ +#ifndef MAX_INITIAL_POST_SIZE +#define MAX_INITIAL_POST_SIZE (64*1024) +#endif + +#ifndef TINY_INITIAL_POST_SIZE +#define TINY_INITIAL_POST_SIZE 1024 +#endif + +#endif +#endif diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c new file mode 100644 index 0000000..1b03a55 --- /dev/null +++ b/Utilities/cmcurl/lib/http_chunks.c @@ -0,0 +1,360 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +#ifndef CURL_DISABLE_HTTP +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include + +#include "urldata.h" /* it includes http_chunks.h */ +#include "sendf.h" /* for the client write stuff */ + +#include "content_encoding.h" +#include "http.h" +#include "memory.h" +#include "easyif.h" /* for Curl_convert_to_network prototype */ + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Chunk format (simplified): + * + * [ chunk extension ] CRLF + * CRLF + * + * Highlights from RFC2616 section 3.6 say: + + The chunked encoding modifies the body of a message in order to + transfer it as a series of chunks, each with its own size indicator, + followed by an OPTIONAL trailer containing entity-header fields. This + allows dynamically produced content to be transferred along with the + information necessary for the recipient to verify that it has + received the full message. + + Chunked-Body = *chunk + last-chunk + trailer + CRLF + + chunk = chunk-size [ chunk-extension ] CRLF + chunk-data CRLF + chunk-size = 1*HEX + last-chunk = 1*("0") [ chunk-extension ] CRLF + + chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) + chunk-ext-name = token + chunk-ext-val = token | quoted-string + chunk-data = chunk-size(OCTET) + trailer = *(entity-header CRLF) + + The chunk-size field is a string of hex digits indicating the size of + the chunk. The chunked encoding is ended by any chunk whose size is + zero, followed by the trailer, which is terminated by an empty line. + + */ + + +void Curl_httpchunk_init(struct connectdata *conn) +{ + struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk; + chunk->hexindex=0; /* start at 0 */ + chunk->dataleft=0; /* no data left yet! */ + chunk->state = CHUNK_HEX; /* we get hex first! */ +} + +/* + * 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 connectdata *conn, + char *datap, + ssize_t datalen, + ssize_t *wrotep) +{ + CURLcode result=CURLE_OK; + struct SessionHandle *data = conn->data; + struct Curl_chunker *ch = &data->reqdata.proto.http->chunk; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + size_t piece; + size_t length = (size_t)datalen; + size_t *wrote = (size_t *)wrotep; + + *wrote = 0; /* nothing's written yet */ + + while(length) { + switch(ch->state) { + case CHUNK_HEX: + /* Check for an ASCII hex digit. + We avoid the use of isxdigit to accommodate non-ASCII hosts. */ + if((*datap >= 0x30 && *datap <= 0x39) /* 0-9 */ + || (*datap >= 0x41 && *datap <= 0x46) /* A-F */ + || (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */ + if(ch->hexindex < MAXNUM_SIZE) { + ch->hexbuffer[ch->hexindex] = *datap; + datap++; + length--; + ch->hexindex++; + } + else { + return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ + } + } + else { + if(0 == ch->hexindex) { + /* This is illegal data, we received junk where we expected + a hexadecimal digit. */ + return CHUNKE_ILLEGAL_HEX; + } + /* length and datap are unmodified */ + ch->hexbuffer[ch->hexindex]=0; +#ifdef CURL_DOES_CONVERSIONS + /* convert to host encoding before calling strtoul */ + result = Curl_convert_from_network(conn->data, + ch->hexbuffer, + ch->hexindex); + if(result != CURLE_OK) { + /* Curl_convert_from_network calls failf if unsuccessful */ + /* Treat it as a bad hex character */ + return(CHUNKE_ILLEGAL_HEX); + } +#endif /* CURL_DOES_CONVERSIONS */ + ch->datasize=strtoul(ch->hexbuffer, NULL, 16); + ch->state = CHUNK_POSTHEX; + } + break; + + case CHUNK_POSTHEX: + /* In this state, we're waiting for CRLF to arrive. We support + this to allow so called chunk-extensions to show up here + before the CRLF comes. */ + if(*datap == 0x0d) + ch->state = CHUNK_CR; + length--; + datap++; + break; + + case CHUNK_CR: + /* waiting for the LF */ + if(*datap == 0x0a) { + /* we're now expecting data to come, unless size was zero! */ + if(0 == ch->datasize) { + if (conn->bits.trailerHdrPresent!=TRUE) { + /* No Trailer: header found - revert to original Curl processing */ + ch->state = CHUNK_STOP; + if (1 == length) { + /* This is the final byte, return right now */ + return CHUNKE_STOP; + } + } + else { + ch->state = CHUNK_TRAILER; /* attempt to read trailers */ + conn->trlPos=0; + } + } + else + ch->state = CHUNK_DATA; + } + else + /* previously we got a fake CR, go back to CR waiting! */ + ch->state = CHUNK_CR; + datap++; + length--; + break; + + case CHUNK_DATA: + /* we get pure and fine data + + We expect another 'datasize' of data. We have 'length' right now, + it can be more or less than 'datasize'. Get the smallest piece. + */ + piece = (ch->datasize >= length)?length:ch->datasize; + + /* Write the data portion available */ +#ifdef HAVE_LIBZ + switch (data->reqdata.keep.content_encoding) { + case IDENTITY: +#endif + if(!k->ignorebody) + result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, + piece); +#ifdef HAVE_LIBZ + break; + + case DEFLATE: + /* update data->reqdata.keep.str to point to the chunk data. */ + data->reqdata.keep.str = datap; + result = Curl_unencode_deflate_write(conn, &data->reqdata.keep, + (ssize_t)piece); + break; + + case GZIP: + /* update data->reqdata.keep.str to point to the chunk data. */ + data->reqdata.keep.str = datap; + result = Curl_unencode_gzip_write(conn, &data->reqdata.keep, + (ssize_t)piece); + break; + + case COMPRESS: + default: + failf (conn->data, + "Unrecognized content encoding type. " + "libcurl understands `identity', `deflate' and `gzip' " + "content encodings."); + return CHUNKE_BAD_ENCODING; + } +#endif + + if(result) + return CHUNKE_WRITE_ERROR; + + *wrote += piece; + + ch->datasize -= piece; /* decrease amount left to expect */ + datap += piece; /* move read pointer forward */ + length -= piece; /* decrease space left in this round */ + + if(0 == ch->datasize) + /* end of data this round, we now expect a trailing CRLF */ + ch->state = CHUNK_POSTCR; + break; + + case CHUNK_POSTCR: + if(*datap == 0x0d) { + ch->state = CHUNK_POSTLF; + datap++; + length--; + } + else + return CHUNKE_BAD_CHUNK; + break; + + case CHUNK_POSTLF: + if(*datap == 0x0a) { + /* + * The last one before we go back to hex state and start all + * over. + */ + Curl_httpchunk_init(conn); + datap++; + length--; + } + else + return CHUNKE_BAD_CHUNK; + break; + + case CHUNK_TRAILER: + /* conn->trailer is assumed to be freed in url.c on a + connection basis */ + if (conn->trlPos >= conn->trlMax) { + char *ptr; + if(conn->trlMax) { + conn->trlMax *= 2; + ptr = (char*)realloc(conn->trailer,conn->trlMax); + } + else { + conn->trlMax=128; + ptr = (char*)malloc(conn->trlMax); + } + if(!ptr) + return CHUNKE_OUT_OF_MEMORY; + conn->trailer = ptr; + } + conn->trailer[conn->trlPos++]=*datap; + + if(*datap == 0x0d) + ch->state = CHUNK_TRAILER_CR; + else { + datap++; + length--; + } + break; + + case CHUNK_TRAILER_CR: + if(*datap == 0x0d) { + ch->state = CHUNK_TRAILER_POSTCR; + datap++; + length--; + } + else + return CHUNKE_BAD_CHUNK; + break; + + case CHUNK_TRAILER_POSTCR: + if (*datap == 0x0a) { + conn->trailer[conn->trlPos++]=0x0a; + conn->trailer[conn->trlPos]=0; + if (conn->trlPos==2) { + ch->state = CHUNK_STOP; + return CHUNKE_STOP; + } + else { +#ifdef CURL_DOES_CONVERSIONS + /* Convert to host encoding before calling Curl_client_write */ + result = Curl_convert_from_network(conn->data, + conn->trailer, + conn->trlPos); + if(result != CURLE_OK) { + /* Curl_convert_from_network calls failf if unsuccessful */ + /* Treat it as a bad chunk */ + return(CHUNKE_BAD_CHUNK); + } +#endif /* CURL_DOES_CONVERSIONS */ + Curl_client_write(conn, CLIENTWRITE_HEADER, + conn->trailer, conn->trlPos); + } + ch->state = CHUNK_TRAILER; + conn->trlPos=0; + datap++; + length--; + } + else + return CHUNKE_BAD_CHUNK; + break; + + case CHUNK_STOP: + /* If we arrive here, there is data left in the end of the buffer + even if there's no more chunks to read */ + ch->dataleft = length; + return CHUNKE_STOP; /* return stop */ + default: + return CHUNKE_STATE_ERROR; + } + } + return CHUNKE_OK; +} +#endif /* CURL_DISABLE_HTTP */ diff --git a/Utilities/cmcurl/lib/http_chunks.h b/Utilities/cmcurl/lib/http_chunks.h new file mode 100644 index 0000000..211818a --- /dev/null +++ b/Utilities/cmcurl/lib/http_chunks.h @@ -0,0 +1,104 @@ +#ifndef __HTTP_CHUNKS_H +#define __HTTP_CHUNKS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +/* + * The longest possible hexadecimal number we support in a chunked transfer. + * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul() + * to convert it, we "only" support 2^32 bytes chunk data. + */ +#define MAXNUM_SIZE 16 + +typedef enum { + CHUNK_FIRST, /* never use */ + + /* In this we await and buffer all hexadecimal digits until we get one + that isn't a hexadecimal digit. When done, we go POSTHEX */ + CHUNK_HEX, + + /* We have received the hexadecimal digit and we eat all characters until + we get a CRLF pair. When we see a CR we go to the CR state. */ + CHUNK_POSTHEX, + + /* A single CR has been found and we should get a LF right away in this + state or we go back to POSTHEX. When LF is received, we go to DATA. + If the size given was zero, we set state to STOP and return. */ + CHUNK_CR, + + /* We eat the amount of data specified. When done, we move on to the + POST_CR state. */ + CHUNK_DATA, + + /* POSTCR should get a CR and nothing else, then move to POSTLF */ + CHUNK_POSTCR, + + /* POSTLF should get a LF and nothing else, then move back to HEX as the + CRLF combination marks the end of a chunk */ + CHUNK_POSTLF, + + /* This is mainly used to really mark that we're out of the game. + NOTE: that there's a 'dataleft' 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 + is CRLF */ + CHUNK_TRAILER, + + /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. + Next char must be a LF */ + CHUNK_TRAILER_CR, + + /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be + 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, + + CHUNK_LAST /* never use */ + +} ChunkyState; + +typedef enum { + CHUNKE_STOP = -1, + CHUNKE_OK = 0, + CHUNKE_TOO_LONG_HEX = 1, + CHUNKE_ILLEGAL_HEX, + CHUNKE_BAD_CHUNK, + CHUNKE_WRITE_ERROR, + CHUNKE_STATE_ERROR, + CHUNKE_BAD_ENCODING, + CHUNKE_OUT_OF_MEMORY, + CHUNKE_LAST +} CHUNKcode; + +struct Curl_chunker { + char hexbuffer[ MAXNUM_SIZE + 1]; + int hexindex; + ChunkyState state; + size_t datasize; + size_t dataleft; /* untouched data amount at the end of the last buffer */ +}; + +#endif diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c new file mode 100644 index 0000000..c223784 --- /dev/null +++ b/Utilities/cmcurl/lib/http_digest.c @@ -0,0 +1,504 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "strequal.h" +#include "base64.h" +#include "md5.h" +#include "http_digest.h" +#include "strtok.h" +#include "url.h" /* for Curl_safefree() */ +#include "memory.h" +#include "easyif.h" /* included for Curl_convert_... prototypes */ + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +/* Test example headers: + +WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" +Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" + +*/ + +CURLdigest Curl_input_digest(struct connectdata *conn, + bool proxy, + char *header) /* rest of the *-authenticate: + header */ +{ + bool more = TRUE; + char *token = NULL; + char *tmp = NULL; + bool foundAuth = FALSE; + bool foundAuthInt = FALSE; + struct SessionHandle *data=conn->data; + bool before = FALSE; /* got a nonce before */ + struct digestdata *d; + + if(proxy) { + d = &data->state.proxydigest; + } + else { + d = &data->state.digest; + } + + /* skip initial whitespaces */ + while(*header && ISSPACE(*header)) + header++; + + if(checkprefix("Digest", header)) { + header += strlen("Digest"); + + /* If we already have received a nonce, keep that in mind */ + if(d->nonce) + before = TRUE; + + /* clear off any former leftovers and init to defaults */ + Curl_digest_cleanup_one(d); + + while(more) { + char value[32]; + char content[128]; + size_t totlen=0; + + while(*header && ISSPACE(*header)) + header++; + + /* how big can these strings be? */ + if((2 == sscanf(header, "%31[^=]=\"%127[^\"]\"", + value, content)) || + /* try the same scan but without quotes around the content but don't + include the possibly trailing comma */ + (2 == sscanf(header, "%31[^=]=%127[^,]", + value, content)) ) { + if(strequal(value, "nonce")) { + d->nonce = strdup(content); + if(!d->nonce) + return CURLDIGEST_NOMEM; + } + else if(strequal(value, "stale")) { + if(strequal(content, "true")) { + d->stale = TRUE; + d->nc = 1; /* we make a new nonce now */ + } + } + else if(strequal(value, "realm")) { + d->realm = strdup(content); + if(!d->realm) + return CURLDIGEST_NOMEM; + } + else if(strequal(value, "opaque")) { + d->opaque = strdup(content); + if(!d->opaque) + return CURLDIGEST_NOMEM; + } + else if(strequal(value, "qop")) { + char *tok_buf; + /* tokenize the list and choose auth if possible, use a temporary + clone of the buffer since strtok_r() ruins it */ + tmp = strdup(content); + if(!tmp) + return CURLDIGEST_NOMEM; + token = strtok_r(tmp, ",", &tok_buf); + while (token != NULL) { + if (strequal(token, "auth")) { + foundAuth = TRUE; + } + else if (strequal(token, "auth-int")) { + foundAuthInt = TRUE; + } + token = strtok_r(NULL, ",", &tok_buf); + } + free(tmp); + /*select only auth o auth-int. Otherwise, ignore*/ + if (foundAuth) { + d->qop = strdup("auth"); + if(!d->qop) + return CURLDIGEST_NOMEM; + } + else if (foundAuthInt) { + d->qop = strdup("auth-int"); + if(!d->qop) + return CURLDIGEST_NOMEM; + } + } + else if(strequal(value, "algorithm")) { + d->algorithm = strdup(content); + if(!d->algorithm) + return CURLDIGEST_NOMEM; + if(strequal(content, "MD5-sess")) + d->algo = CURLDIGESTALGO_MD5SESS; + else if(strequal(content, "MD5")) + d->algo = CURLDIGESTALGO_MD5; + else + return CURLDIGEST_BADALGO; + } + else { + /* unknown specifier, ignore it! */ + } + totlen = strlen(value)+strlen(content)+1; + + if(header[strlen(value)+1] == '\"') + /* the contents were within quotes, then add 2 for them to the + length */ + totlen += 2; + } + else + break; /* we're done here */ + + header += totlen; + if(',' == *header) + /* allow the list to be comma-separated */ + header++; + } + /* We had a nonce since before, and we got another one now without + 'stale=true'. This means we provided bad credentials in the previous + request */ + if(before && !d->stale) + return CURLDIGEST_BAD; + + /* We got this header without a nonce, that's a bad Digest line! */ + if(!d->nonce) + return CURLDIGEST_BAD; + } + else + /* else not a digest, get out */ + return CURLDIGEST_NONE; + + return CURLDIGEST_FINE; +} + +/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ +static void md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i=0; i<16; i++) + snprintf((char *)&dest[i*2], 3, "%02x", source[i]); +} + +CURLcode Curl_output_digest(struct connectdata *conn, + bool proxy, + unsigned char *request, + unsigned char *uripath) +{ + /* We have a Digest setup for this, use it! Now, to get all the details for + this sorted out, I must urge you dear friend to read up on the RFC2617 + section 3.2.2, */ + unsigned char md5buf[16]; /* 16 bytes/128 bits */ + unsigned char request_digest[33]; + unsigned char *md5this; + unsigned char *ha1; + unsigned char ha2[33];/* 32 digits and 1 zero byte */ + char cnoncebuf[7]; + char *cnonce; + char *tmp = NULL; + struct timeval now; + + char **allocuserpwd; + char *userp; + char *passwdp; + struct auth *authp; + + struct SessionHandle *data = conn->data; + struct digestdata *d; +#ifdef CURL_DOES_CONVERSIONS + CURLcode rc; +/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. + It converts digest text to ASCII so the MD5 will be correct for + what ultimately goes over the network. +*/ +#define CURL_OUTPUT_DIGEST_CONV(a, b) \ + rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ + if (rc != CURLE_OK) { \ + free(b); \ + return rc; \ + } +#else +#define CURL_OUTPUT_DIGEST_CONV(a, b) +#endif /* CURL_DOES_CONVERSIONS */ + + if(proxy) { + d = &data->state.proxydigest; + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + authp = &data->state.authproxy; + } + else { + d = &data->state.digest; + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + passwdp = conn->passwd; + authp = &data->state.authhost; + } + + /* not set means empty */ + if(!userp) + userp=(char *)""; + + if(!passwdp) + passwdp=(char *)""; + + if(!d->nonce) { + authp->done = FALSE; + return CURLE_OK; + } + authp->done = TRUE; + + if(!d->nc) + d->nc = 1; + + if(!d->cnonce) { + /* Generate a cnonce */ + now = Curl_tvnow(); + snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec); + if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce)) + d->cnonce = cnonce; + else + return CURLE_OUT_OF_MEMORY; + } + + /* + if the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + if the algorithm is "MD5-sess" then: + + A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) + ":" unq(nonce-value) ":" unq(cnonce-value) + */ + + md5this = (unsigned char *) + aprintf("%s:%s:%s", userp, d->realm, passwdp); + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); /* free this again */ + + ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */ + if(!ha1) + return CURLE_OUT_OF_MEMORY; + + md5_to_ascii(md5buf, ha1); + + if(d->algo == CURLDIGESTALGO_MD5SESS) { + /* nonce and cnonce are OUTSIDE the hash */ + tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, (unsigned char *)tmp); + free(tmp); /* free this again */ + md5_to_ascii(md5buf, ha1); + } + + /* + If the "qop" directive's value is "auth" or is unspecified, then A2 is: + + A2 = Method ":" digest-uri-value + + If the "qop" value is "auth-int", then A2 is: + + A2 = Method ":" digest-uri-value ":" H(entity-body) + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + md5this = (unsigned char *)aprintf("%s:%s", request, uripath); + if(!md5this) { + free(ha1); + return CURLE_OUT_OF_MEMORY; + } + + if (d->qop && strequal(d->qop, "auth-int")) { + /* We don't support auth-int at the moment. I can't see a easy way to get + entity-body here */ + /* TODO: Append H(entity-body)*/ + } + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); /* free this again */ + md5_to_ascii(md5buf, ha2); + + if (d->qop) { + md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", + ha1, + d->nonce, + d->nc, + d->cnonce, + d->qop, + ha2); + } + else { + md5this = (unsigned char *)aprintf("%s:%s:%s", + ha1, + d->nonce, + ha2); + } + free(ha1); + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); /* free this again */ + md5_to_ascii(md5buf, request_digest); + + /* for test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" + */ + + Curl_safefree(*allocuserpwd); + + if (d->qop) { + *allocuserpwd = + aprintf( "%sAuthorization: Digest " + "username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=\"%s\", " + "response=\"%s\"", + proxy?"Proxy-":"", + userp, + d->realm, + d->nonce, + uripath, /* this is the PATH part of the URL */ + d->cnonce, + d->nc, + d->qop, + request_digest); + + if(strequal(d->qop, "auth")) + d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded + which tells to the server how many times you are using the + same nonce in the qop=auth mode. */ + } + else { + *allocuserpwd = + aprintf( "%sAuthorization: Digest " + "username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + proxy?"Proxy-":"", + userp, + d->realm, + d->nonce, + uripath, /* this is the PATH part of the URL */ + request_digest); + } + if(!*allocuserpwd) + return CURLE_OUT_OF_MEMORY; + + /* Add optional fields */ + if(d->opaque) { + /* append opaque */ + tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + free(*allocuserpwd); + *allocuserpwd = tmp; + } + + if(d->algorithm) { + /* append algorithm */ + tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + free(*allocuserpwd); + *allocuserpwd = tmp; + } + + /* append CRLF to the userpwd header */ + tmp = (char*) realloc(*allocuserpwd, strlen(*allocuserpwd) + 3 + 1); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + strcat(tmp, "\r\n"); + *allocuserpwd = tmp; + + return CURLE_OK; +} + +void Curl_digest_cleanup_one(struct digestdata *d) +{ + if(d->nonce) + free(d->nonce); + d->nonce = NULL; + + if(d->cnonce) + free(d->cnonce); + d->cnonce = NULL; + + if(d->realm) + free(d->realm); + d->realm = NULL; + + if(d->opaque) + free(d->opaque); + d->opaque = NULL; + + if(d->qop) + free(d->qop); + d->qop = NULL; + + if(d->algorithm) + free(d->algorithm); + d->algorithm = NULL; + + d->nc = 0; + d->algo = CURLDIGESTALGO_MD5; /* default algorithm */ + d->stale = FALSE; /* default means normal, not stale */ +} + + +void Curl_digest_cleanup(struct SessionHandle *data) +{ + Curl_digest_cleanup_one(&data->state.digest); + Curl_digest_cleanup_one(&data->state.proxydigest); +} + +#endif diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h new file mode 100644 index 0000000..6cf0259 --- /dev/null +++ b/Utilities/cmcurl/lib/http_digest.h @@ -0,0 +1,58 @@ +#ifndef __HTTP_DIGEST_H +#define __HTTP_DIGEST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +typedef enum { + CURLDIGEST_NONE, /* not a digest */ + CURLDIGEST_BAD, /* a digest, but one we don't like */ + CURLDIGEST_BADALGO, /* unsupported algorithm requested */ + CURLDIGEST_NOMEM, + CURLDIGEST_FINE, /* a digest we act on */ + + CURLDIGEST_LAST /* last entry in this enum, don't use */ +} CURLdigest; + +enum { + CURLDIGESTALGO_MD5, + CURLDIGESTALGO_MD5SESS +}; + +/* this is for digest header input */ +CURLdigest Curl_input_digest(struct connectdata *conn, + bool proxy, char *header); + +/* this is for creating digest header output */ +CURLcode Curl_output_digest(struct connectdata *conn, + bool proxy, + unsigned char *request, + unsigned char *uripath); +void Curl_digest_cleanup_one(struct digestdata *dig); + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) +void Curl_digest_cleanup(struct SessionHandle *data); +#else +#define Curl_digest_cleanup(x) do {} while(0) +#endif + +#endif diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c new file mode 100644 index 0000000..bdfeefa --- /dev/null +++ b/Utilities/cmcurl/lib/http_negotiate.c @@ -0,0 +1,327 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +#ifdef HAVE_GSSAPI +#ifdef HAVE_GSSMIT +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#endif + +#ifndef CURL_DISABLE_HTTP + /* -- WIN32 approved -- */ +#include +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "strequal.h" +#include "base64.h" +#include "http_negotiate.h" +#include "memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +static int +get_gss_name(struct connectdata *conn, gss_name_t *server) +{ + struct negotiatedata *neg_ctx = &conn->data->state.negotiate; + OM_uint32 major_status, minor_status; + gss_buffer_desc token = GSS_C_EMPTY_BUFFER; + char name[2048]; + const char* service; + + /* GSSAPI implementation by Globus (known as GSI) requires the name to be + of form "/" instead of @ (ie. slash instead + of at-sign). Also GSI servers are often identified as 'host' not 'khttp'. + Change following lines if you want to use GSI */ + + /* IIS uses the @ form but uses 'http' as the service name */ + + if (neg_ctx->gss) + service = "KHTTP"; + else + service = "HTTP"; + + token.length = strlen(service) + 1 + strlen(conn->host.name) + 1; + if (token.length + 1 > sizeof(name)) + return EMSGSIZE; + + snprintf(name, sizeof(name), "%s@%s", service, conn->host.name); + + token.value = (void *) name; + major_status = gss_import_name(&minor_status, + &token, + GSS_C_NT_HOSTBASED_SERVICE, + server); + + return GSS_ERROR(major_status) ? -1 : 0; +} + +static void +log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix) +{ + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char buf[1024]; + size_t len; + + snprintf(buf, sizeof(buf), "%s", prefix); + len = strlen(buf); + do { + maj_stat = gss_display_status (&min_stat, + error_status, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if (sizeof(buf) > len + status_string.length + 1) { + snprintf(buf + len, sizeof(buf) - len, + ": %s", (char*) status_string.value); + len += status_string.length; + } + gss_release_buffer(&min_stat, &status_string); + } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); + + infof(conn->data, "%s", buf); +} + +int Curl_input_negotiate(struct connectdata *conn, char *header) +{ + struct negotiatedata *neg_ctx = &conn->data->state.negotiate; + OM_uint32 major_status, minor_status, minor_status2; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + int ret; + size_t len; + bool gss; + const char* protocol; + + while(*header && ISSPACE(*header)) + header++; + if(checkprefix("GSS-Negotiate", header)) { + protocol = "GSS-Negotiate"; + gss = TRUE; + } + else if (checkprefix("Negotiate", header)) { + protocol = "Negotiate"; + gss = FALSE; + } + else + return -1; + + if (neg_ctx->context) { + if (neg_ctx->gss != gss) { + return -1; + } + } + else { + neg_ctx->protocol = protocol; + neg_ctx->gss = gss; + } + + if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { + /* We finished succesfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_cleanup_negotiate(conn->data); + return -1; + } + + if (neg_ctx->server_name == NULL && + (ret = get_gss_name(conn, &neg_ctx->server_name))) + return ret; + + header += strlen(neg_ctx->protocol); + while(*header && ISSPACE(*header)) + header++; + + len = strlen(header); + if (len > 0) { + int rawlen = Curl_base64_decode(header, (unsigned char **)&input_token.value); + if (rawlen < 0) + return -1; + input_token.length = rawlen; + +#ifdef HAVE_SPNEGO /* Handle SPNEGO */ + if (checkprefix("Negotiate", header)) { + ASN1_OBJECT * object = NULL; + int rc = 1; + unsigned char * spnegoToken = NULL; + size_t spnegoTokenLength = 0; + unsigned char * mechToken = NULL; + size_t mechTokenLength = 0; + + spnegoToken = malloc(input_token.length); + if (input_token.value == NULL) + return ENOMEM; + spnegoTokenLength = input_token.length; + + object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); + if (!parseSpnegoTargetToken(spnegoToken, + spnegoTokenLength, + NULL, + NULL, + &mechToken, + &mechTokenLength, + NULL, + NULL)) { + free(spnegoToken); + spnegoToken = NULL; + infof(conn->data, "Parse SPNEGO Target Token failed\n"); + } + else { + free(input_token.value); + input_token.value = NULL; + input_token.value = malloc(mechTokenLength); + memcpy(input_token.value, mechToken,mechTokenLength); + input_token.length = mechTokenLength; + free(mechToken); + mechToken = NULL; + infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); + } + } +#endif + } + + major_status = gss_init_sec_context(&minor_status, + GSS_C_NO_CREDENTIAL, + &neg_ctx->context, + neg_ctx->server_name, + GSS_C_NO_OID, + GSS_C_DELEG_FLAG, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + NULL, + &output_token, + NULL, + NULL); + if (input_token.length > 0) + gss_release_buffer(&minor_status2, &input_token); + neg_ctx->status = major_status; + if (GSS_ERROR(major_status)) { + /* Curl_cleanup_negotiate(conn->data) ??? */ + log_gss_error(conn, minor_status, + (char *)"gss_init_sec_context() failed: "); + return -1; + } + + if (output_token.length == 0) { + return -1; + } + + neg_ctx->output_token = output_token; + /* conn->bits.close = FALSE; */ + + return 0; +} + + +CURLcode Curl_output_negotiate(struct connectdata *conn) +{ + struct negotiatedata *neg_ctx = &conn->data->state.negotiate; + OM_uint32 minor_status; + char *encoded = NULL; + int len; + +#ifdef HAVE_SPNEGO /* Handle SPNEGO */ + if (checkprefix("Negotiate",neg_ctx->protocol)) { + ASN1_OBJECT * object = NULL; + int rc = 1; + unsigned char * spnegoToken = NULL; + size_t spnegoTokenLength = 0; + unsigned char * responseToken = NULL; + size_t responseTokenLength = 0; + + responseToken = malloc(neg_ctx->output_token.length); + if ( responseToken == NULL) + return CURLE_OUT_OF_MEMORY; + memcpy(responseToken, neg_ctx->output_token.value, + neg_ctx->output_token.length); + responseTokenLength = neg_ctx->output_token.length; + + object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); + if (!makeSpnegoInitialToken (object, + responseToken, + responseTokenLength, + &spnegoToken, + &spnegoTokenLength)) { + free(responseToken); + responseToken = NULL; + infof(conn->data, "Make SPNEGO Initial Token failed\n"); + } + else { + free(neg_ctx->output_token.value); + responseToken = NULL; + neg_ctx->output_token.value = malloc(spnegoTokenLength); + memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength); + neg_ctx->output_token.length = spnegoTokenLength; + free(spnegoToken); + spnegoToken = NULL; + infof(conn->data, "Make SPNEGO Initial Token succeeded\n"); + } + } +#endif + len = Curl_base64_encode(conn->data, + neg_ctx->output_token.value, + neg_ctx->output_token.length, + &encoded); + + if (len < 0) + return CURLE_OUT_OF_MEMORY; + + conn->allocptr.userpwd = + aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded); + free(encoded); + gss_release_buffer(&minor_status, &neg_ctx->output_token); + return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; +} + +void Curl_cleanup_negotiate(struct SessionHandle *data) +{ + OM_uint32 minor_status; + struct negotiatedata *neg_ctx = &data->state.negotiate; + + if (neg_ctx->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER); + + if (neg_ctx->output_token.length != 0) + gss_release_buffer(&minor_status, &neg_ctx->output_token); + + if (neg_ctx->server_name != GSS_C_NO_NAME) + gss_release_name(&minor_status, &neg_ctx->server_name); + + memset(neg_ctx, 0, sizeof(*neg_ctx)); +} + + +#endif +#endif diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h new file mode 100644 index 0000000..ce0d083 --- /dev/null +++ b/Utilities/cmcurl/lib/http_negotiate.h @@ -0,0 +1,39 @@ +#ifndef __HTTP_NEGOTIATE_H +#define __HTTP_NEGOTIATE_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifdef HAVE_GSSAPI + +/* this is for Negotiate header input */ +int Curl_input_negotiate(struct connectdata *conn, char *header); + +/* this is for creating Negotiate header output */ +CURLcode Curl_output_negotiate(struct connectdata *conn); + +void Curl_cleanup_negotiate(struct SessionHandle *data); + +#endif + +#endif diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c new file mode 100644 index 0000000..aff1bb1 --- /dev/null +++ b/Utilities/cmcurl/lib/http_ntlm.c @@ -0,0 +1,1111 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +/* NTLM details: + + http://davenport.sourceforge.net/ntlm.html + http://www.innovation.ch/java/ntlm.html + + Another implementation: + http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp + +*/ + +#ifndef CURL_DISABLE_HTTP +#ifdef USE_NTLM + +#define DEBUG_ME 0 + +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "urldata.h" +#include "easyif.h" /* for Curl_convert_... prototypes */ +#include "sendf.h" +#include "strequal.h" +#include "base64.h" +#include "http_ntlm.h" +#include "url.h" +#include "memory.h" +#include "ssluse.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* "NTLMSSP" signature is always in ASCII regardless of the platform */ +#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" + +#ifndef USE_WINDOWS_SSPI + +#include +#include +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x00907001L +#define DES_key_schedule des_key_schedule +#define DES_cblock des_cblock +#define DES_set_odd_parity des_set_odd_parity +#define DES_set_key des_set_key +#define DES_ecb_encrypt des_ecb_encrypt + +/* This is how things were done in the old days */ +#define DESKEY(x) x +#define DESKEYARG(x) x +#else +/* Modern version */ +#define DESKEYARG(x) *x +#define DESKEY(x) &x +#endif + +#else + +#include + +/* Handle of security.dll or secur32.dll, depending on Windows version */ +static HMODULE s_hSecDll = NULL; +/* Pointer to SSPI dispatch table */ +static PSecurityFunctionTable s_pSecFn = NULL; + +#endif + +/* The last #include file should be: */ +#include "memdebug.h" + +/* Define this to make the type-3 message include the NT response message */ +#define USE_NTRESPONSES 1 + +/* Define this to make the type-3 message include the NTLM2Session response + message, requires USE_NTRESPONSES. */ +#define USE_NTLM2SESSION 1 + +#ifndef USE_WINDOWS_SSPI +/* this function converts from the little endian format used in the incoming + package to whatever endian format we're using natively */ +static unsigned int readint_le(unsigned char *buf) /* must point to a + 4 bytes buffer*/ +{ + return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | + ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); +} +#endif + +#if DEBUG_ME +# define DEBUG_OUT(x) x +static void print_flags(FILE *handle, unsigned long flags) +{ + if(flags & NTLMFLAG_NEGOTIATE_UNICODE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); + if(flags & NTLMFLAG_NEGOTIATE_OEM) + fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); + if(flags & NTLMFLAG_REQUEST_TARGET) + fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); + if(flags & (1<<3)) + fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); + if(flags & NTLMFLAG_NEGOTIATE_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); + if(flags & NTLMFLAG_NEGOTIATE_SEAL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); + if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); + if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_NETWARE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); + if(flags & (1<<10)) + fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); + if(flags & (1<<11)) + fprintf(handle, "NTLMFLAG_UNKNOWN_11 "); + if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); + if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); + if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); + if(flags & NTLMFLAG_TARGET_TYPE_SERVER) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); + if(flags & NTLMFLAG_TARGET_TYPE_SHARE) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); + if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) + fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) + fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); + if(flags & (1<<24)) + fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); + if(flags & (1<<25)) + fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); + if(flags & (1<<26)) + fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); + if(flags & (1<<27)) + fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); + if(flags & (1<<28)) + fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); + if(flags & NTLMFLAG_NEGOTIATE_128) + fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); + if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); + if(flags & NTLMFLAG_NEGOTIATE_56) + fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); +} + +static void print_hex(FILE *handle, const char *buf, size_t len) +{ + const char *p = buf; + fprintf(stderr, "0x"); + while (len-- > 0) + fprintf(stderr, "%02.2x", (unsigned int)*p++); +} +#else +# define DEBUG_OUT(x) +#endif + +/* + (*) = A "security buffer" is a triplet consisting of two shorts and one + long: + + 1. a 'short' containing the length of the buffer in bytes + 2. a 'short' containing the allocated space for the buffer in bytes + 3. a 'long' containing the offset to the start of the buffer from the + beginning of the NTLM message, in bytes. +*/ + + +CURLntlm Curl_input_ntlm(struct connectdata *conn, + bool proxy, /* if proxy or not */ + char *header) /* rest of the www-authenticate: + header */ +{ + /* point to the correct struct with this */ + struct ntlmdata *ntlm; +#ifndef USE_WINDOWS_SSPI + static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; +#endif + + ntlm = proxy?&conn->proxyntlm:&conn->ntlm; + + /* skip initial whitespaces */ + while(*header && ISSPACE(*header)) + header++; + + if(checkprefix("NTLM", header)) { + header += strlen("NTLM"); + + while(*header && ISSPACE(*header)) + header++; + + if(*header) { + /* We got a type-2 message here: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x02000000) + 12 Target Name security buffer(*) + 20 Flags long + 24 Challenge 8 bytes + (32) Context (optional) 8 bytes (two consecutive longs) + (40) Target Information (optional) security buffer(*) + 32 (48) start of data block + */ + size_t size; + unsigned char *buffer; + size = Curl_base64_decode(header, &buffer); + if(!buffer) + return CURLNTLM_BAD; + + ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */ + +#ifdef USE_WINDOWS_SSPI + ntlm->type_2 = malloc(size+1); + if (ntlm->type_2 == NULL) { + free(buffer); + return CURLE_OUT_OF_MEMORY; + } + ntlm->n_type_2 = size; + memcpy(ntlm->type_2, buffer, size); +#else + ntlm->flags = 0; + + if((size < 32) || + (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || + (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) { + /* This was not a good enough type-2 message */ + free(buffer); + return CURLNTLM_BAD; + } + + ntlm->flags = readint_le(&buffer[20]); + memcpy(ntlm->nonce, &buffer[24], 8); + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); + print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n nonce="); + print_hex(stderr, (char *)ntlm->nonce, 8); + fprintf(stderr, "\n****\n"); + fprintf(stderr, "**** Header %s\n ", header); + }); + + free(buffer); +#endif + } + else { + if(ntlm->state >= NTLMSTATE_TYPE1) + return CURLNTLM_BAD; + + ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */ + } + } + return CURLNTLM_FINE; +} + +#ifndef USE_WINDOWS_SSPI + +/* + * 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(unsigned char *key_56, + DES_key_schedule DESKEYARG(ks)) +{ + DES_cblock key; + + 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); + + DES_set_odd_parity(&key); + DES_set_key(&key, ks); +} + + /* + * takes a 21 byte array and treats it as 3 56-bit DES keys. The + * 8 byte plaintext is encrypted with each key and the resulting 24 + * bytes are stored in the results array. + */ +static void lm_resp(unsigned char *keys, + unsigned char *plaintext, + unsigned char *results) +{ + DES_key_schedule ks; + + setup_des_key(keys, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys+7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys+14, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), + DESKEY(ks), DES_ENCRYPT); +} + + +/* + * Set up lanmanager hashed password + */ +static void mk_lm_hash(struct SessionHandle *data, + char *password, + unsigned char *lmbuffer /* 21 bytes */) +{ + unsigned char pw[14]; + static const unsigned char magic[] = { + 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ + }; + unsigned int i; + size_t len = strlen(password); + + if (len > 14) + len = 14; + + for (i=0; itype_2) { + free(ntlm->type_2); + ntlm->type_2 = NULL; + } + if (ntlm->has_handles) { + s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); + s_pSecFn->FreeCredentialsHandle(&ntlm->handle); + ntlm->has_handles = 0; + } + if (ntlm->p_identity) { + if (ntlm->identity.User) free(ntlm->identity.User); + if (ntlm->identity.Password) free(ntlm->identity.Password); + if (ntlm->identity.Domain) free(ntlm->identity.Domain); + ntlm->p_identity = NULL; + } +} + +#endif + +#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) +#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ + (((x) >>16)&0xff), (((x)>>24) & 0xff) + +#define HOSTNAME_MAX 1024 + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn, + bool proxy) +{ + const char *domain=""; /* empty */ + char host [HOSTNAME_MAX+ 1] = ""; /* empty */ +#ifndef USE_WINDOWS_SSPI + size_t domlen = strlen(domain); + size_t hostlen = strlen(host); + size_t hostoff; /* host name offset */ + size_t domoff; /* domain name offset */ +#endif + size_t size; + char *base64=NULL; + unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very + long */ + + /* point to the address of the pointer that holds the string to sent to the + server, which is for a plain host or for a HTTP proxy */ + char **allocuserpwd; + + /* point to the name and password for this */ + char *userp; + char *passwdp; + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + struct auth *authp; + + curlassert(conn); + curlassert(conn->data); + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + passwdp = conn->passwd; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp=(char *)""; + + if(!passwdp) + passwdp=(char *)""; + +#ifdef USE_WINDOWS_SSPI + /* If security interface is not yet initialized try to do this */ + if (s_hSecDll == NULL) { + /* Determine Windows version. Security functions are located in + * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP + * contain both these DLLs (security.dll just forwards calls to + * secur32.dll) + */ + OSVERSIONINFO osver; + osver.dwOSVersionInfoSize = sizeof(osver); + GetVersionEx(&osver); + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT + && osver.dwMajorVersion == 4) + s_hSecDll = LoadLibrary("security.dll"); + else + s_hSecDll = LoadLibrary("secur32.dll"); + if (s_hSecDll != NULL) { + INIT_SECURITY_INTERFACE pInitSecurityInterface; + pInitSecurityInterface = + (INIT_SECURITY_INTERFACE)GetProcAddress(s_hSecDll, + "InitSecurityInterfaceA"); + if (pInitSecurityInterface != NULL) + s_pSecFn = pInitSecurityInterface(); + } + } + if (s_pSecFn == NULL) + return CURLE_RECV_ERROR; +#endif + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: /* for the weird cases we (re)start here */ +#ifdef USE_WINDOWS_SSPI + { + SecBuffer buf; + SecBufferDesc desc; + SECURITY_STATUS status; + ULONG attrs; + const char *user; + int domlen; + TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ + + ntlm_sspi_cleanup(ntlm); + + user = strchr(userp, '\\'); + if (!user) + user = strchr(userp, '/'); + + if (user) { + domain = userp; + domlen = user - userp; + user++; + } + else { + user = userp; + domain = ""; + domlen = 0; + } + + if (user && *user) { + /* note: initialize all of this before doing the mallocs so that + * it can be cleaned up later without leaking memory. + */ + ntlm->p_identity = &ntlm->identity; + memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); + if ((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) + return CURLE_OUT_OF_MEMORY; + ntlm->identity.UserLength = strlen(user); + if ((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) + return CURLE_OUT_OF_MEMORY; + ntlm->identity.PasswordLength = strlen(passwdp); + if ((ntlm->identity.Domain = malloc(domlen+1)) == NULL) + return CURLE_OUT_OF_MEMORY; + strncpy((char *)ntlm->identity.Domain, domain, domlen); + ntlm->identity.Domain[domlen] = '\0'; + ntlm->identity.DomainLength = domlen; + ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + } + else { + ntlm->p_identity = NULL; + } + + if (s_pSecFn->AcquireCredentialsHandle( + NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, + NULL, NULL, &ntlm->handle, &tsDummy + ) != SEC_E_OK) { + return CURLE_OUT_OF_MEMORY; + } + + desc.ulVersion = SECBUFFER_VERSION; + desc.cBuffers = 1; + desc.pBuffers = &buf; + buf.cbBuffer = sizeof(ntlmbuf); + buf.BufferType = SECBUFFER_TOKEN; + buf.pvBuffer = ntlmbuf; + + status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL, + (char *) host, + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, + NULL, 0, + &ntlm->c_handle, &desc, + &attrs, &tsDummy); + + if (status == SEC_I_COMPLETE_AND_CONTINUE || + status == SEC_I_CONTINUE_NEEDED) { + s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); + } + else if (status != SEC_E_OK) { + s_pSecFn->FreeCredentialsHandle(&ntlm->handle); + return CURLE_RECV_ERROR; + } + + ntlm->has_handles = 1; + size = buf.cbBuffer; + } +#else + hostoff = 0; + domoff = hostoff + hostlen; /* This is 0: remember that host and domain + are empty */ + + /* Create and send a type-1 message: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x01000000) + 12 Flags long + 16 Supplied Domain security buffer(*) + 24 Supplied Workstation security buffer(*) + 32 start of data block + + */ +#if USE_NTLM2SESSION +#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY +#else +#define NTLM2FLAG 0 +#endif + snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c" + "\x01%c%c%c" /* 32-bit type = 1 */ + "%c%c%c%c" /* 32-bit NTLM flag field */ + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host name offset */ + "%c%c" /* 2 zeroes */ + "%s" /* host name */ + "%s", /* domain string */ + 0, /* trailing zero */ + 0,0,0, /* part of type-1 long */ + + LONGQUARTET( + NTLMFLAG_NEGOTIATE_OEM| + NTLMFLAG_REQUEST_TARGET| + NTLMFLAG_NEGOTIATE_NTLM_KEY| + NTLM2FLAG| + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN + ), + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0,0, + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0,0, + host /* this is empty */, domain /* this is empty */); + + /* initial packet length */ + size = 32 + hostlen + domlen; +#endif + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM| + NTLMFLAG_REQUEST_TARGET| + NTLMFLAG_NEGOTIATE_NTLM_KEY| + NTLM2FLAG| + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + NTLMFLAG_NEGOTIATE_OEM| + NTLMFLAG_REQUEST_TARGET| + NTLMFLAG_NEGOTIATE_NTLM_KEY| + NTLM2FLAG| + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + print_flags(stderr, + NTLMFLAG_NEGOTIATE_OEM| + NTLMFLAG_REQUEST_TARGET| + NTLMFLAG_NEGOTIATE_NTLM_KEY| + NTLM2FLAG| + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + fprintf(stderr, "\n****\n"); + }); + + /* now size is the size of the base64 encoded package size */ + size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); + + if(size >0 ) { + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy?"Proxy-":"", + base64); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + free(base64); + } + else + return CURLE_OUT_OF_MEMORY; /* FIX TODO */ + + break; + + case NTLMSTATE_TYPE2: + /* We received the type-2 message already, create a type-3 message: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x03000000) + 12 LM/LMv2 Response security buffer(*) + 20 NTLM/NTLMv2 Response security buffer(*) + 28 Domain Name security buffer(*) + 36 User Name security buffer(*) + 44 Workstation Name security buffer(*) + (52) Session Key (optional) security buffer(*) + (60) Flags (optional) long + 52 (64) start of data block + + */ + + { +#ifdef USE_WINDOWS_SSPI + SecBuffer type_2, type_3; + SecBufferDesc type_2_desc, type_3_desc; + SECURITY_STATUS status; + ULONG attrs; + TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ + + type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = type_3_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2; + type_3_desc.pBuffers = &type_3; + + type_2.BufferType = SECBUFFER_TOKEN; + type_2.pvBuffer = ntlm->type_2; + type_2.cbBuffer = ntlm->n_type_2; + type_3.BufferType = SECBUFFER_TOKEN; + type_3.pvBuffer = ntlmbuf; + type_3.cbBuffer = sizeof(ntlmbuf); + + status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, &ntlm->c_handle, + (char *) host, + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, &type_2_desc, + 0, &ntlm->c_handle, &type_3_desc, + &attrs, &tsDummy); + + if (status != SEC_E_OK) + return CURLE_RECV_ERROR; + + size = type_3.cbBuffer; + + ntlm_sspi_cleanup(ntlm); + +#else + int lmrespoff; + unsigned char lmresp[24]; /* fixed-size */ +#if USE_NTRESPONSES + int ntrespoff; + unsigned char ntresp[24]; /* fixed-size */ +#endif + size_t useroff; + const char *user; + size_t userlen; + + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if (user) { + domain = userp; + domlen = (user - domain); + user++; + } + else + user = userp; + userlen = strlen(user); + + if (gethostname(host, HOSTNAME_MAX)) { + infof(conn->data, "gethostname() failed, continuing without!"); + hostlen = 0; + } + else { + /* If the workstation if configured with a full DNS name (i.e. + * workstation.somewhere.net) gethostname() returns the fully qualified + * name, which NTLM doesn't like. + */ + char *dot = strchr(host, '.'); + if (dot) + *dot = '\0'; + hostlen = strlen(host); + } + +#if USE_NTLM2SESSION + /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ + if (ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { + unsigned char ntbuffer[0x18]; + unsigned char tmp[0x18]; + unsigned char md5sum[MD5_DIGEST_LENGTH]; + MD5_CTX MD5; + unsigned char random[8]; + + /* Need to create 8 bytes random data */ + Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */ + RAND_bytes(random,8); + + /* 8 bytes random data as challenge in lmresp */ + memcpy(lmresp,random,8); + /* Pad with zeros */ + memset(lmresp+8,0,0x10); + + /* Fill tmp with challenge(nonce?) + random */ + memcpy(tmp,&ntlm->nonce[0],8); + memcpy(tmp+8,random,8); + + MD5_Init(&MD5); + MD5_Update(&MD5, tmp, 16); + MD5_Final(md5sum, &MD5); + /* We shall only use the first 8 bytes of md5sum, + but the des code in lm_resp only encrypt the first 8 bytes */ + mk_nt_hash(conn->data, passwdp, ntbuffer); + lm_resp(ntbuffer, md5sum, ntresp); + + /* End of NTLM2 Session code */ + } + else { +#endif + +#if USE_NTRESPONSES + unsigned char ntbuffer[0x18]; +#endif + unsigned char lmbuffer[0x18]; + +#if USE_NTRESPONSES + mk_nt_hash(conn->data, passwdp, ntbuffer); + lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); +#endif + + mk_lm_hash(conn->data, passwdp, lmbuffer); + lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + /* A safer but less compatible alternative is: + * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); + * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ +#if USE_NTLM2SESSION + } +#endif + + lmrespoff = 64; /* size of the message header */ +#if USE_NTRESPONSES + ntrespoff = lmrespoff + 0x18; + domoff = ntrespoff + 0x18; +#else + domoff = lmrespoff + 0x18; +#endif + useroff = domoff + domlen; + hostoff = useroff + userlen; + + /* Create the big type-3 message binary blob */ + size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf), + NTLMSSP_SIGNATURE "%c" + "\x03%c%c%c" /* type-3, 32 bits */ + + "%c%c" /* LanManager length */ + "%c%c" /* LanManager allocated space */ + "%c%c" /* LanManager offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* NT-response length */ + "%c%c" /* NT-response allocated space */ + "%c%c" /* NT-response offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* user length */ + "%c%c" /* user allocated space */ + "%c%c" /* user offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* session key length (unknown purpose) */ + "%c%c" /* session key allocated space (unknown purpose) */ + "%c%c" /* session key offset (unknown purpose) */ + "%c%c" /* 2 zeroes */ + + "%c%c%c%c" /* flags */ + + /* domain string */ + /* user string */ + /* host string */ + /* LanManager response */ + /* NT response */ + , + 0, /* zero termination */ + 0,0,0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, + +#if USE_NTRESPONSES + SHORTPAIR(0x18), /* NT-response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(ntrespoff), + 0x0, 0x0, +#else + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, +#endif + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0x0, 0x0, + + SHORTPAIR(userlen), + SHORTPAIR(userlen), + SHORTPAIR(useroff), + 0x0, 0x0, + + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0x0, 0x0, + + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + + LONGQUARTET(ntlm->flags)); + DEBUG_OUT(assert(size==64)); + + DEBUG_OUT(assert(size == lmrespoff)); + /* We append the binary hashes */ + if(size < (sizeof(ntlmbuf) - 0x18)) { + memcpy(&ntlmbuf[size], lmresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE3 header lmresp="); + print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); + }); + +#if USE_NTRESPONSES + if(size < (sizeof(ntlmbuf) - 0x18)) { + DEBUG_OUT(assert(size == ntrespoff)); + memcpy(&ntlmbuf[size], ntresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "\n ntresp="); + print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); + }); + +#endif + + DEBUG_OUT({ + fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", + LONGQUARTET(ntlm->flags), ntlm->flags); + print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n****\n"); + }); + + + /* Make sure that the domain, user and host strings fit in the target + buffer before we copy them there. */ + if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) { + failf(conn->data, "user + domain + host name too big"); + return CURLE_OUT_OF_MEMORY; + } + + curlassert(size == domoff); + memcpy(&ntlmbuf[size], domain, domlen); + size += domlen; + + curlassert(size == useroff); + memcpy(&ntlmbuf[size], user, userlen); + size += userlen; + + curlassert(size == hostoff); + memcpy(&ntlmbuf[size], host, hostlen); + size += hostlen; + +#ifdef CURL_DOES_CONVERSIONS + /* convert domain, user, and host to ASCII but leave the rest as-is */ + if(CURLE_OK != Curl_convert_to_network(conn->data, + (char *)&ntlmbuf[domoff], + size-domoff)) { + return CURLE_CONV_FAILED; + } +#endif /* CURL_DOES_CONVERSIONS */ + +#endif + + /* convert the binary blob into base64 */ + size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); + + if(size >0 ) { + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy?"Proxy-":"", + base64); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + free(base64); + } + else + return CURLE_OUT_OF_MEMORY; /* FIX TODO */ + + ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ + authp->done = TRUE; + } + break; + + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + if(*allocuserpwd) { + free(*allocuserpwd); + *allocuserpwd=NULL; + } + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + + +void +Curl_ntlm_cleanup(struct connectdata *conn) +{ +#ifdef USE_WINDOWS_SSPI + ntlm_sspi_cleanup(&conn->ntlm); + ntlm_sspi_cleanup(&conn->proxyntlm); + if (s_hSecDll != NULL) { + FreeLibrary(s_hSecDll); + s_hSecDll = NULL; + s_pSecFn = NULL; + } +#else + (void)conn; +#endif +} + +#endif /* USE_NTLM */ +#endif /* !CURL_DISABLE_HTTP */ diff --git a/Utilities/cmcurl/lib/http_ntlm.h b/Utilities/cmcurl/lib/http_ntlm.h new file mode 100644 index 0000000..a8de220 --- /dev/null +++ b/Utilities/cmcurl/lib/http_ntlm.h @@ -0,0 +1,146 @@ +#ifndef __HTTP_NTLM_H +#define __HTTP_NTLM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +typedef enum { + CURLNTLM_NONE, /* not a ntlm */ + CURLNTLM_BAD, /* an ntlm, but one we don't like */ + CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */ + CURLNTLM_FINE, /* an ntlm we act on */ + + CURLNTLM_LAST /* last entry in this enum, don't use */ +} CURLntlm; + +/* this is for ntlm header input */ +CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); + +void Curl_ntlm_cleanup(struct connectdata *conn); +#ifndef USE_NTLM +#define Curl_ntlm_cleanup(x) +#endif + + +/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ + +#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) +/* Indicates that Unicode strings are supported for use in security buffer + data. */ + +#define NTLMFLAG_NEGOTIATE_OEM (1<<1) +/* Indicates that OEM strings are supported for use in security buffer data. */ + +#define NTLMFLAG_REQUEST_TARGET (1<<2) +/* Requests that the server's authentication realm be included in the Type 2 + message. */ + +/* unknown (1<<3) */ +#define NTLMFLAG_NEGOTIATE_SIGN (1<<4) +/* Specifies that authenticated communication between the client and server + should carry a digital signature (message integrity). */ + +#define NTLMFLAG_NEGOTIATE_SEAL (1<<5) +/* Specifies that authenticated communication between the client and server + should be encrypted (message confidentiality). */ + +#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6) +/* unknown purpose */ + +#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7) +/* Indicates that the LAN Manager session key should be used for signing and + sealing authenticated communications. */ + +#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8) +/* unknown purpose */ + +#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9) +/* Indicates that NTLM authentication is being used. */ + +/* unknown (1<<10) */ +/* unknown (1<<11) */ + +#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12) +/* Sent by the client in the Type 1 message to indicate that a desired + authentication realm is included in the message. */ + +#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13) +/* Sent by the client in the Type 1 message to indicate that the client + workstation's name is included in the message. */ + +#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14) +/* Sent by the server to indicate that the server and client are on the same + machine. Implies that the client may use a pre-established local security + context rather than responding to the challenge. */ + +#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15) +/* Indicates that authenticated communication between the client and server + should be signed with a "dummy" signature. */ + +#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16) +/* Sent by the server in the Type 2 message to indicate that the target + authentication realm is a domain. */ + +#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17) +/* Sent by the server in the Type 2 message to indicate that the target + authentication realm is a server. */ + +#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18) +/* Sent by the server in the Type 2 message to indicate that the target + authentication realm is a share. Presumably, this is for share-level + authentication. Usage is unclear. */ + +#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19) +/* Indicates that the NTLM2 signing and sealing scheme should be used for + protecting authenticated communications. */ + +#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20) +/* unknown purpose */ + +#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21) +/* unknown purpose */ + +#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22) +/* unknown purpose */ + +#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23) +/* Sent by the server in the Type 2 message to indicate that it is including a + Target Information block in the message. */ + +/* unknown (1<24) */ +/* unknown (1<25) */ +/* unknown (1<26) */ +/* unknown (1<27) */ +/* unknown (1<28) */ + +#define NTLMFLAG_NEGOTIATE_128 (1<<29) +/* Indicates that 128-bit encryption is supported. */ + +#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30) +/* unknown purpose */ + +#define NTLMFLAG_NEGOTIATE_56 (1<<31) +/* Indicates that 56-bit encryption is supported. */ +#endif diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c new file mode 100644 index 0000000..b4a98c6 --- /dev/null +++ b/Utilities/cmcurl/lib/if2ip.c @@ -0,0 +1,134 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "if2ip.h" + +/* + * This test can probably be simplified to #if defined(SIOCGIFADDR) and + * moved after the following includes. + */ +#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN__) && \ + !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE) && \ + !defined(_AMIGASF) && !defined(__minix) + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +/* This must be before net/if.h for AIX 3.2 to enjoy life */ +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif + +#ifdef VMS +#include +#endif + +#include "inet_ntop.h" +#include "memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#define SYS_ERROR -1 + +char *Curl_if2ip(const char *interface, char *buf, int buf_size) +{ + int dummy; + char *ip=NULL; + + if(!interface) + return NULL; + + dummy = socket(AF_INET, SOCK_STREAM, 0); + if (SYS_ERROR == dummy) { + return NULL; + } + else { + struct ifreq req; + size_t len = strlen(interface); + memset(&req, 0, sizeof(req)); + if(len >= sizeof(req.ifr_name)) + return NULL; /* this can't be a fine interface name */ + memcpy(req.ifr_name, interface, len+1); + req.ifr_addr.sa_family = AF_INET; +#ifdef IOCTL_3_ARGS + if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) { +#else + if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) { +#endif + sclose(dummy); + return NULL; + } + else { + struct in_addr in; + + struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr; + memcpy(&in, &s->sin_addr, sizeof(in)); + ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size); + } + sclose(dummy); + } + return ip; +} + +/* -- end of if2ip() -- */ +#else +char *Curl_if2ip(const char *interf, char *buf, int buf_size) +{ + (void) interf; + (void) buf; + (void) buf_size; + return NULL; +} +#endif diff --git a/Utilities/cmcurl/lib/if2ip.h b/Utilities/cmcurl/lib/if2ip.h new file mode 100644 index 0000000..4e86e2b --- /dev/null +++ b/Utilities/cmcurl/lib/if2ip.h @@ -0,0 +1,67 @@ +#ifndef __IF2IP_H +#define __IF2IP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +extern char *Curl_if2ip(const char *interf, char *buf, int buf_size); + +#ifdef __INTERIX +#include + +/* Nedelcho Stanev's work-around for SFU 3.0 */ +struct ifreq { +#define IFNAMSIZ 16 +#define IFHWADDRLEN 6 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + } ifr_ifru; +}; + +/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the + C code. */ +#define ifr_dstaddr ifr_addr + +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ + +#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ +#endif /* interix */ + +#endif diff --git a/Utilities/cmcurl/lib/inet_ntoa_r.h b/Utilities/cmcurl/lib/inet_ntoa_r.h new file mode 100644 index 0000000..c6c9bd8 --- /dev/null +++ b/Utilities/cmcurl/lib/inet_ntoa_r.h @@ -0,0 +1,44 @@ +#ifndef __INET_NTOA_R_H +#define __INET_NTOA_R_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_INET_NTOA_R_2_ARGS +/* + * uClibc 0.9.26 (at least) doesn't define this prototype. The buffer + * must be at least 16 characters long. + */ +char *inet_ntoa_r(const struct in_addr in, char buffer[]); + +#else +/* + * My solaris 5.6 system running gcc 2.8.1 does *not* have this prototype + * in any system include file! Isn't that weird? + */ +char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen); + +#endif + +#endif diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c new file mode 100644 index 0000000..9381963 --- /dev/null +++ b/Utilities/cmcurl/lib/inet_ntop.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Original code by Paul Vixie. "curlified" by Gisle Vanem. + */ + +#include "setup.h" + +#ifndef HAVE_INET_NTOP + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +#include + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "inet_ntop.h" + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +/* this platform has a inet_ntoa_r() function, but no proto declared anywhere + so we include our own proto to make compilers happy */ +#include "inet_ntoa_r.h" +#endif + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +#ifdef USE_WINSOCK +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define SET_ERRNO(e) WSASetLastError(errno = (e)) +#else +#define SET_ERRNO(e) errno = e +#endif + +/* + * Format an IPv4 address, more or less like inet_ntoa(). + * + * Returns `dst' (as a const) + * Note: + * - 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) +{ +#if defined(HAVE_INET_NTOA_R_2_ARGS) + const char *ptr; + curlassert(size >= 16); + ptr = inet_ntoa_r(*(struct in_addr*)src, dst); + return (char *)memmove(dst, ptr, strlen(ptr)+1); + +#elif defined(HAVE_INET_NTOA_R) + return inet_ntoa_r(*(struct in_addr*)src, dst, size); + +#else + const char *addr = inet_ntoa(*(struct in_addr*)src); + + if (strlen(addr) >= size) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + return strcpy(dst, addr); +#endif +} + +#ifdef ENABLE_IPV6 +/* + * Convert IPv6 binary address into presentation (printable) format. + */ +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 + * 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. + */ + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char *tp; + struct { + long base; + long len; + } best, cur; + unsigned long words[IN6ADDRSZ / INT16SZ]; + int i; + + /* Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof(words)); + for (i = 0; i < IN6ADDRSZ; i++) + words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); + + best.base = -1; + cur.base = -1; + best.len = 0; + cur.len = 0; + + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + if ((cur.base != -1) && (best.base == -1 || cur.len > best.len)) + best = cur; + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? + */ + if (best.base != -1 && i >= best.base && i < (best.base + best.len)) + { + if (i == best.base) + *tp++ = ':'; + continue; + } + + /* Are we following an initial run of 0x00s or any real hex? + */ + if (i != 0) + *tp++ = ':'; + + /* Is this address an encapsulated IPv4? + */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + tp += strlen(tp); + break; + } + tp += snprintf(tp, 5, "%lx", words[i]); + } + + /* Was it a trailing run of 0x00's? + */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + return strcpy (dst, tmp); +} +#endif /* ENABLE_IPV6 */ + +/* + * Convert a network format address to presentation format. + * + * Returns pointer to presentation format address (`buf'), + * Returns NULL on error (see errno). + */ +char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) +{ + switch (af) { + case AF_INET: + return inet_ntop4((const unsigned char*)src, buf, size); +#ifdef ENABLE_IPV6 + case AF_INET6: + return inet_ntop6((const unsigned char*)src, buf, size); +#endif + default: + SET_ERRNO(EAFNOSUPPORT); + return NULL; + } +} +#endif /* HAVE_INET_NTOP */ diff --git a/Utilities/cmcurl/lib/inet_ntop.h b/Utilities/cmcurl/lib/inet_ntop.h new file mode 100644 index 0000000..54d64bd --- /dev/null +++ b/Utilities/cmcurl/lib/inet_ntop.h @@ -0,0 +1,37 @@ +#ifndef __INET_NTOP_H +#define __INET_NTOP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); + +#ifdef HAVE_INET_NTOP +#ifdef HAVE_ARPA_INET_H +#include +#endif +#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size) +#endif + +#endif /* __INET_NTOP_H */ diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c new file mode 100644 index 0000000..9b9f88b --- /dev/null +++ b/Utilities/cmcurl/lib/inet_pton.c @@ -0,0 +1,241 @@ +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "setup.h" + +#ifndef HAVE_INET_PTON + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +#include + +#include "inet_pton.h" + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +#ifdef USE_WINSOCK +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#endif + +/* + * 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); +#ifdef ENABLE_IPV6 +static int inet_pton6(const char *src, unsigned char *dst); +#endif + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * 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 wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +Curl_inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, (unsigned char *)dst)); +#ifdef ENABLE_IPV6 +#ifndef AF_INET6 +#define AF_INET6 (AF_MAX+1) /* just to let this compile */ +#endif + case AF_INET6: + return (inet_pton6(src, (unsigned char *)dst)); +#endif + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + tp = tmp; + *tp = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int val = *tp * 10 + (unsigned int)(pch - digits); + + if (val > 255) + return (0); + *tp = val; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + /* bcopy(tmp, dst, INADDRSZ); */ + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +#ifdef ENABLE_IPV6 +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(const char *src, unsigned char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), 0, IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + /* bcopy(tmp, dst, IN6ADDRSZ); */ + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} +#endif /* ENABLE_IPV6 */ + +#endif /* HAVE_INET_PTON */ diff --git a/Utilities/cmcurl/lib/inet_pton.h b/Utilities/cmcurl/lib/inet_pton.h new file mode 100644 index 0000000..a659a97 --- /dev/null +++ b/Utilities/cmcurl/lib/inet_pton.h @@ -0,0 +1,42 @@ +#ifndef __INET_PTON_H +#define __INET_PTON_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +int Curl_inet_pton(int, const char *, void *); + +#ifdef HAVE_INET_PTON + +#if defined(HAVE_NO_INET_PTON_PROTO) +int inet_pton(int af, const char *src, void *dst); +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif +#define Curl_inet_pton(x,y,z) inet_pton(x,y,z) +#endif + +#endif /* __INET_PTON_H */ diff --git a/Utilities/cmcurl/lib/krb4.c b/Utilities/cmcurl/lib/krb4.c new file mode 100644 index 0000000..f2b91df --- /dev/null +++ b/Utilities/cmcurl/lib/krb4.c @@ -0,0 +1,425 @@ +/* This source code was modified by Martin Hedenfalk for + * use in Curl. Martin's latest changes were done 2000-09-18. + * + * It has since been patched away like a madman by Daniel Stenberg to make it + * better applied to curl conditions, and to make it not use globals, pollute + * name space and more. + * + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * Copyright (c) 2004 - 2007 Daniel Stenberg + * All rights reserved. + * + * 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. + * + * $Id$ + */ + +#include "setup.h" + +#ifndef CURL_DISABLE_FTP +#ifdef HAVE_KRB4 + +#include +#ifdef HAVE_NETDB_H +#include +#endif +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include /* for getpid() */ +#endif + +#include "urldata.h" +#include "base64.h" +#include "ftp.h" +#include "sendf.h" +#include "krb4.h" +#include "memory.h" + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +/* The last #include file should be: */ +#include "memdebug.h" + +#define LOCAL_ADDR (&conn->local_addr) +#define REMOTE_ADDR conn->ip_addr->ai_addr +#define myctladdr LOCAL_ADDR +#define hisctladdr REMOTE_ADDR + +struct krb4_data { + des_cblock key; + des_key_schedule schedule; + char name[ANAME_SZ]; + char instance[INST_SZ]; + char realm[REALM_SZ]; +}; + +#ifndef HAVE_STRLCPY +/* if it ever goes non-static, make it Curl_ prefixed! */ +static size_t +strlcpy (char *dst, const char *src, size_t dst_sz) +{ + size_t n; + char *p; + + for (p = dst, n = 0; + n + 1 < dst_sz && *src != '\0'; + ++p, ++src, ++n) + *p = *src; + *p = '\0'; + if (*src == '\0') + return n; + else + return n + strlen (src); +} +#else +size_t strlcpy (char *dst, const char *src, size_t dst_sz); +#endif + +static int +krb4_check_prot(void *app_data, int level) +{ + app_data = NULL; /* prevent compiler warning */ + if(level == prot_confidential) + return -1; + return 0; +} + +static int +krb4_decode(void *app_data, void *buf, int len, int level, + struct connectdata *conn) +{ + MSG_DAT m; + int e; + struct krb4_data *d = app_data; + + if(level == prot_safe) + e = krb_rd_safe(buf, len, &d->key, + (struct sockaddr_in *)REMOTE_ADDR, + (struct sockaddr_in *)LOCAL_ADDR, &m); + else + e = krb_rd_priv(buf, len, d->schedule, &d->key, + (struct sockaddr_in *)REMOTE_ADDR, + (struct sockaddr_in *)LOCAL_ADDR, &m); + if(e) { + struct SessionHandle *data = conn->data; + infof(data, "krb4_decode: %s\n", krb_get_err_text(e)); + return -1; + } + memmove(buf, m.app_data, m.app_length); + return m.app_length; +} + +static int +krb4_overhead(void *app_data, int level, int len) +{ + /* no arguments are used, just init them to prevent compiler warnings */ + app_data = NULL; + level = 0; + len = 0; + return 31; +} + +static int +krb4_encode(void *app_data, void *from, int length, int level, void **to, + struct connectdata *conn) +{ + struct krb4_data *d = app_data; + *to = malloc(length + 31); + if(level == prot_safe) + return krb_mk_safe(from, *to, length, &d->key, + (struct sockaddr_in *)LOCAL_ADDR, + (struct sockaddr_in *)REMOTE_ADDR); + else if(level == prot_private) + return krb_mk_priv(from, *to, length, d->schedule, &d->key, + (struct sockaddr_in *)LOCAL_ADDR, + (struct sockaddr_in *)REMOTE_ADDR); + else + return -1; +} + +static int +mk_auth(struct krb4_data *d, KTEXT adat, + const char *service, char *host, int checksum) +{ + int ret; + CREDENTIALS cred; + char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ]; + + strlcpy(sname, service, sizeof(sname)); + strlcpy(inst, krb_get_phost(host), sizeof(inst)); + strlcpy(realm, krb_realmofhost(host), sizeof(realm)); + ret = krb_mk_req(adat, sname, inst, realm, checksum); + if(ret) + return ret; + strlcpy(sname, service, sizeof(sname)); + strlcpy(inst, krb_get_phost(host), sizeof(inst)); + strlcpy(realm, krb_realmofhost(host), sizeof(realm)); + ret = krb_get_cred(sname, inst, realm, &cred); + memmove(&d->key, &cred.session, sizeof(des_cblock)); + des_key_sched(&d->key, d->schedule); + memset(&cred, 0, sizeof(cred)); + return ret; +} + +#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM +int krb_get_our_ip_for_realm(char *, struct in_addr *); +#endif + +static int +krb4_auth(void *app_data, struct connectdata *conn) +{ + int ret; + char *p; + unsigned char *ptr; + size_t len; + KTEXT_ST adat; + MSG_DAT msg_data; + int checksum; + u_int32_t cs; + struct krb4_data *d = app_data; + char *host = conn->host.name; + ssize_t nread; + int l = sizeof(conn->local_addr); + struct SessionHandle *data = conn->data; + CURLcode result; + + if(getsockname(conn->sock[FIRSTSOCKET], + (struct sockaddr *)LOCAL_ADDR, &l) < 0) + perror("getsockname()"); + + checksum = getpid(); + ret = mk_auth(d, &adat, "ftp", host, checksum); + if(ret == KDC_PR_UNKNOWN) + ret = mk_auth(d, &adat, "rcmd", host, checksum); + if(ret) { + infof(data, "%s\n", krb_get_err_text(ret)); + return AUTH_CONTINUE; + } + +#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM + if (krb_get_config_bool("nat_in_use")) { + struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR; + struct in_addr natAddr; + + if (krb_get_our_ip_for_realm(krb_realmofhost(host), + &natAddr) != KSUCCESS + && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS) + infof(data, "Can't get address for realm %s\n", + krb_realmofhost(host)); + else { + if (natAddr.s_addr != localaddr->sin_addr.s_addr) { +#ifdef HAVE_INET_NTOA_R + char ntoa_buf[64]; + char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf)); +#else + char *ip = (char *)inet_ntoa(natAddr); +#endif + infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip); + localaddr->sin_addr = natAddr; + } + } + } +#endif + + if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) { + Curl_failf(data, "Out of memory base64-encoding"); + return AUTH_CONTINUE; + } + + result = Curl_ftpsendf(conn, "ADAT %s", p); + + free(p); + + if(result) + return -2; + + if(Curl_GetFTPResponse(&nread, conn, NULL)) + return -1; + + if(data->state.buffer[0] != '2'){ + Curl_failf(data, "Server didn't accept auth data"); + return AUTH_ERROR; + } + + p = strstr(data->state.buffer, "ADAT="); + if(!p) { + Curl_failf(data, "Remote host didn't send adat reply"); + return AUTH_ERROR; + } + p += 5; + len = Curl_base64_decode(p, &ptr); + if(len > sizeof(adat.dat)-1) { + free(ptr); + len=0; + } + if(!len || !ptr) { + Curl_failf(data, "Failed to decode base64 from server"); + return AUTH_ERROR; + } + memcpy((char *)adat.dat, ptr, len); + free(ptr); + adat.length = len; + ret = krb_rd_safe(adat.dat, adat.length, &d->key, + (struct sockaddr_in *)hisctladdr, + (struct sockaddr_in *)myctladdr, &msg_data); + if(ret) { + Curl_failf(data, "Error reading reply from server: %s", + krb_get_err_text(ret)); + return AUTH_ERROR; + } + krb_get_int(msg_data.app_data, &cs, 4, 0); + if(cs - checksum != 1) { + Curl_failf(data, "Bad checksum returned from server"); + return AUTH_ERROR; + } + return AUTH_OK; +} + +struct Curl_sec_client_mech Curl_krb4_client_mech = { + "KERBEROS_V4", + sizeof(struct krb4_data), + NULL, /* init */ + krb4_auth, + NULL, /* end */ + krb4_check_prot, + krb4_overhead, + krb4_encode, + krb4_decode +}; + +CURLcode Curl_krb_kauth(struct connectdata *conn) +{ + des_cblock key; + des_key_schedule schedule; + KTEXT_ST tkt, tktcopy; + char *name; + char *p; + char passwd[100]; + size_t tmp; + ssize_t nread; + int save; + CURLcode result; + unsigned char *ptr; + + save = Curl_set_command_prot(conn, prot_private); + + result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user); + + if(result) + return result; + + result = Curl_GetFTPResponse(&nread, conn, NULL); + if(result) + return result; + + if(conn->data->state.buffer[0] != '3'){ + Curl_set_command_prot(conn, save); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + p = strstr(conn->data->state.buffer, "T="); + if(!p) { + Curl_failf(conn->data, "Bad reply from server"); + Curl_set_command_prot(conn, save); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + p += 2; + tmp = Curl_base64_decode(p, &ptr); + if(tmp >= sizeof(tkt.dat)) { + free(ptr); + tmp=0; + } + if(!tmp || !ptr) { + Curl_failf(conn->data, "Failed to decode base64 in reply.\n"); + Curl_set_command_prot(conn, save); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + memcpy((char *)tkt.dat, ptr, tmp); + free(ptr); + tkt.length = tmp; + tktcopy.length = tkt.length; + + p = strstr(conn->data->state.buffer, "P="); + if(!p) { + Curl_failf(conn->data, "Bad reply from server"); + Curl_set_command_prot(conn, save); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + name = p + 2; + for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++); + *p = 0; + + des_string_to_key (conn->passwd, &key); + des_key_sched(&key, schedule); + + des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat, + tkt.length, + schedule, &key, DES_DECRYPT); + if (strcmp ((char*)tktcopy.dat + 8, + KRB_TICKET_GRANTING_TICKET) != 0) { + afs_string_to_key(passwd, + krb_realmofhost(conn->host.name), + &key); + des_key_sched(&key, schedule); + des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat, + tkt.length, + schedule, &key, DES_DECRYPT); + } + memset(key, 0, sizeof(key)); + memset(schedule, 0, sizeof(schedule)); + memset(passwd, 0, sizeof(passwd)); + if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p) + < 1) { + failf(conn->data, "Out of memory base64-encoding."); + Curl_set_command_prot(conn, save); + return CURLE_OUT_OF_MEMORY; + } + memset (tktcopy.dat, 0, tktcopy.length); + + result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p); + free(p); + if(result) + return result; + + result = Curl_GetFTPResponse(&nread, conn, NULL); + if(result) + return result; + Curl_set_command_prot(conn, save); + + return CURLE_OK; +} + +#endif /* HAVE_KRB4 */ +#endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/lib/krb4.h b/Utilities/cmcurl/lib/krb4.h new file mode 100644 index 0000000..f46416e --- /dev/null +++ b/Utilities/cmcurl/lib/krb4.h @@ -0,0 +1,70 @@ +#ifndef __KRB4_H +#define __KRB4_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +struct Curl_sec_client_mech { + const char *name; + size_t size; + int (*init)(void *); + int (*auth)(void *, struct connectdata *); + void (*end)(void *); + int (*check_prot)(void *, int); + int (*overhead)(void *, int, int); + int (*encode)(void *, void*, int, int, void**, struct connectdata *); + int (*decode)(void *, void*, int, int, struct connectdata *); +}; + + +#define AUTH_OK 0 +#define AUTH_CONTINUE 1 +#define AUTH_ERROR 2 + +extern struct Curl_sec_client_mech Curl_krb4_client_mech; + +CURLcode Curl_krb_kauth(struct connectdata *conn); +int Curl_sec_fflush_fd(struct connectdata *conn, int fd); +int Curl_sec_fprintf (struct connectdata *, FILE *, const char *, ...); +int Curl_sec_getc (struct connectdata *conn, FILE *); +int Curl_sec_putc (struct connectdata *conn, int, FILE *); +int Curl_sec_read (struct connectdata *conn, int, void *, int); +int Curl_sec_read_msg (struct connectdata *conn, char *, int); + +int Curl_sec_vfprintf(struct connectdata *, FILE *, const char *, va_list); +int Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...); +int Curl_sec_vfprintf2(struct connectdata *conn, FILE *, const char *, va_list); +ssize_t Curl_sec_send(struct connectdata *conn, int, char *, int); +int Curl_sec_write(struct connectdata *conn, int, char *, int); + +void Curl_sec_end (struct connectdata *); +int Curl_sec_login (struct connectdata *); +void Curl_sec_prot (int, char **); +int Curl_sec_request_prot (struct connectdata *conn, const char *level); +void Curl_sec_set_protection_level(struct connectdata *conn); +void Curl_sec_status (void); + +enum protection_level Curl_set_command_prot(struct connectdata *, + enum protection_level); + + +#endif diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c new file mode 100644 index 0000000..3e1144d --- /dev/null +++ b/Utilities/cmcurl/lib/ldap.c @@ -0,0 +1,702 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_LDAP +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef NEED_MALLOC_H +#include +#endif +#include + +#if defined(WIN32) +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_DLFCN_H +# include +#endif + +#include "urldata.h" +#include +#include "sendf.h" +#include "escape.h" +#include "transfer.h" +#include "strequal.h" +#include "strtok.h" +#include "ldap.h" +#include "memory.h" +#include "base64.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "memdebug.h" + +/* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl + * pointers in case libcurl was compiled as fastcall (cl -Gr). Watcom + * uses fastcall by default. + */ +#if !defined(WIN32) && !defined(__cdecl) +#define __cdecl +#endif + +#ifndef LDAP_SIZELIMIT_EXCEEDED +#define LDAP_SIZELIMIT_EXCEEDED 4 +#endif +#ifndef LDAP_VERSION2 +#define LDAP_VERSION2 2 +#endif +#ifndef LDAP_VERSION3 +#define LDAP_VERSION3 3 +#endif +#ifndef LDAP_OPT_PROTOCOL_VERSION +#define LDAP_OPT_PROTOCOL_VERSION 0x0011 +#endif + +#define DLOPEN_MODE RTLD_LAZY /*! assume all dlopen() implementations have + this */ + +#if defined(RTLD_LAZY_GLOBAL) /* It turns out some systems use this: */ +# undef DLOPEN_MODE +# define DLOPEN_MODE RTLD_LAZY_GLOBAL +#elif defined(RTLD_GLOBAL) +# undef DLOPEN_MODE +# define DLOPEN_MODE (RTLD_LAZY | RTLD_GLOBAL) +#endif + +#define DYNA_GET_FUNCTION(type, fnc) do { \ + (fnc) = (type)DynaGetFunction(#fnc); \ + if ((fnc) == NULL) \ + return CURLE_FUNCTION_NOT_FOUND; \ + } while (0) + +/*! CygWin etc. configure could set these, but we don't want it. + * Must use WLdap32.dll code. + */ +#if defined(WIN32) +#undef HAVE_DLOPEN +#undef HAVE_LIBDL +#endif + +/* + * We use this ZERO_NULL to avoid picky compiler warnings, + * when assigning a NULL pointer to a function pointer var. + */ + +#define ZERO_NULL 0 + +typedef void * (*dynafunc)(void *input); + +/*********************************************************************** + */ +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) || defined(WIN32) +static void *libldap = NULL; +#if defined(DL_LBER_FILE) +static void *liblber = NULL; +#endif +#endif + +struct bv { + unsigned long bv_len; + char *bv_val; +}; + +static int DynaOpen(const char **mod_name) +{ +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) + if (libldap == NULL) { + /* + * libldap.so can normally resolve its dependency on liblber.so + * automatically, but in broken installation it does not so + * handle it here by opening liblber.so as global. + */ +#ifdef DL_LBER_FILE + *mod_name = DL_LBER_FILE; + liblber = dlopen(*mod_name, DLOPEN_MODE); + if (!liblber) + return 0; +#endif + + /* Assume loading libldap.so will fail if loading of liblber.so failed + */ + *mod_name = DL_LDAP_FILE; + libldap = dlopen(*mod_name, RTLD_LAZY); + } + return (libldap != NULL); + +#elif defined(WIN32) + *mod_name = DL_LDAP_FILE; + if (!libldap) + libldap = (void*)LoadLibrary(*mod_name); + return (libldap != NULL); + +#else + *mod_name = ""; + return (0); +#endif +} + +static void DynaClose(void) +{ +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) + if (libldap) { + dlclose(libldap); + libldap=NULL; + } +#ifdef DL_LBER_FILE + if (liblber) { + dlclose(liblber); + liblber=NULL; + } +#endif +#elif defined(WIN32) + if (libldap) { + FreeLibrary ((HMODULE)libldap); + libldap = NULL; + } +#endif +} + +static dynafunc DynaGetFunction(const char *name) +{ + dynafunc func = (dynafunc)ZERO_NULL; + +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) + if (libldap) { + /* This typecast magic below was brought by Joe Halpin. In ISO C, you + * cannot typecast a data pointer to a function pointer, but that's + * exactly what we need to do here to avoid compiler warnings on picky + * compilers! */ + *(void**) (&func) = dlsym(libldap, name); + } +#elif defined(WIN32) + if (libldap) { + func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name); + } +#else + (void) name; +#endif + return func; +} + +/*********************************************************************** + */ +typedef struct ldap_url_desc { + struct ldap_url_desc *lud_next; + char *lud_scheme; + char *lud_host; + int lud_port; + char *lud_dn; + char **lud_attrs; + int lud_scope; + char *lud_filter; + char **lud_exts; + int lud_crit_exts; +} LDAPURLDesc; + +#ifdef WIN32 +static int _ldap_url_parse (const struct connectdata *conn, + LDAPURLDesc **ludp); +static void _ldap_free_urldesc (LDAPURLDesc *ludp); + +static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc; +#endif + +#ifdef DEBUG_LDAP + #define LDAP_TRACE(x) do { \ + _ldap_trace ("%u: ", __LINE__); \ + _ldap_trace x; \ + } while (0) + + static void _ldap_trace (const char *fmt, ...); +#else + #define LDAP_TRACE(x) ((void)0) +#endif + + +CURLcode Curl_ldap(struct connectdata *conn, bool *done) +{ + CURLcode status = CURLE_OK; + int rc = 0; +#ifndef WIN32 + int (*ldap_url_parse)(char *, LDAPURLDesc **); + void (*ldap_free_urldesc)(void *); +#endif + void *(__cdecl *ldap_init)(char *, int); + int (__cdecl *ldap_simple_bind_s)(void *, char *, char *); + int (__cdecl *ldap_unbind_s)(void *); + int (__cdecl *ldap_search_s)(void *, char *, int, char *, char **, + int, void **); + void *(__cdecl *ldap_first_entry)(void *, void *); + void *(__cdecl *ldap_next_entry)(void *, void *); + char *(__cdecl *ldap_err2string)(int); + char *(__cdecl *ldap_get_dn)(void *, void *); + char *(__cdecl *ldap_first_attribute)(void *, void *, void **); + char *(__cdecl *ldap_next_attribute)(void *, void *, void *); + void **(__cdecl *ldap_get_values_len)(void *, void *, const char *); + void (__cdecl *ldap_value_free_len)(void **); + void (__cdecl *ldap_memfree)(void *); + void (__cdecl *ber_free)(void *, int); + int (__cdecl *ldap_set_option)(void *, int, void *); + + void *server; + LDAPURLDesc *ludp = NULL; + const char *mod_name; + void *result; + void *entryIterator; /*! type should be 'LDAPMessage *' */ + int num = 0; + struct SessionHandle *data=conn->data; + int ldap_proto; + char *val_b64; + size_t val_b64_sz; + + *done = TRUE; /* unconditionally */ + infof(data, "LDAP local: %s\n", data->change.url); + + if (!DynaOpen(&mod_name)) { + failf(data, "The %s LDAP library/libraries couldn't be opened", mod_name); + return CURLE_LIBRARY_NOT_FOUND; + } + + /* The types are needed because ANSI C distinguishes between + * pointer-to-object (data) and pointer-to-function. + */ + DYNA_GET_FUNCTION(void *(__cdecl *)(char *, int), ldap_init); + DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, char *), + ldap_simple_bind_s); + DYNA_GET_FUNCTION(int (__cdecl *)(void *), ldap_unbind_s); +#ifndef WIN32 + DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse); + DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc); +#endif + DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, int, char *, char **, int, + void **), ldap_search_s); + DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_first_entry); + DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_next_entry); + DYNA_GET_FUNCTION(char *(__cdecl *)(int), ldap_err2string); + DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *), ldap_get_dn); + DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void **), + ldap_first_attribute); + DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void *), + ldap_next_attribute); + DYNA_GET_FUNCTION(void **(__cdecl *)(void *, void *, const char *), + ldap_get_values_len); + DYNA_GET_FUNCTION(void (__cdecl *)(void **), ldap_value_free_len); + DYNA_GET_FUNCTION(void (__cdecl *)(void *), ldap_memfree); + DYNA_GET_FUNCTION(void (__cdecl *)(void *, int), ber_free); + DYNA_GET_FUNCTION(int (__cdecl *)(void *, int, void *), ldap_set_option); + + server = (*ldap_init)(conn->host.name, (int)conn->port); + if (server == NULL) { + failf(data, "LDAP local: Cannot connect to %s:%d", + conn->host.name, conn->port); + status = CURLE_COULDNT_CONNECT; + goto quit; + } + + ldap_proto = LDAP_VERSION3; + (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); + rc = (*ldap_simple_bind_s)(server, + conn->bits.user_passwd ? conn->user : NULL, + conn->bits.user_passwd ? conn->passwd : NULL); + if (rc != 0) { + ldap_proto = LDAP_VERSION2; + (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); + rc = (*ldap_simple_bind_s)(server, + conn->bits.user_passwd ? conn->user : NULL, + conn->bits.user_passwd ? conn->passwd : NULL); + } + if (rc != 0) { + failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); + status = CURLE_LDAP_CANNOT_BIND; + goto quit; + } + +#ifdef WIN32 + rc = _ldap_url_parse(conn, &ludp); +#else + rc = (*ldap_url_parse)(data->change.url, &ludp); +#endif + + if (rc != 0) { + failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); + status = CURLE_LDAP_INVALID_URL; + goto quit; + } + + rc = (*ldap_search_s)(server, ludp->lud_dn, ludp->lud_scope, + ludp->lud_filter, ludp->lud_attrs, 0, &result); + + if (rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { + failf(data, "LDAP remote: %s", (*ldap_err2string)(rc)); + status = CURLE_LDAP_SEARCH_FAILED; + goto quit; + } + + for(num = 0, entryIterator = (*ldap_first_entry)(server, result); + entryIterator; + entryIterator = (*ldap_next_entry)(server, entryIterator), num++) + { + void *ber = NULL; /*! is really 'BerElement **' */ + void *attribute; /*! suspicious that this isn't 'const' */ + char *dn = (*ldap_get_dn)(server, entryIterator); + int i; + + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0); + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + + for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber); + attribute; + attribute = (*ldap_next_attribute)(server, entryIterator, ber)) + { + struct bv **vals = (struct bv **) + (*ldap_get_values_len)(server, entryIterator, attribute); + + if (vals != NULL) + { + for (i = 0; (vals[i] != NULL); i++) + { + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0); + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); + if ((strlen(attribute) > 7) && + (strcmp(";binary", + (char *)attribute + + (strlen((char *)attribute) - 7)) == 0)) { + /* Binary attribute, encode to base64. */ + val_b64_sz = Curl_base64_encode(conn->data, + vals[i]->bv_val, + vals[i]->bv_len, + &val_b64); + if (val_b64_sz > 0) { + Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); + free(val_b64); + } + } else + Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, + vals[i]->bv_len); + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + } + + /* Free memory used to store values */ + (*ldap_value_free_len)((void **)vals); + } + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + + (*ldap_memfree)(attribute); + } + (*ldap_memfree)(dn); + if (ber) + (*ber_free)(ber, 0); + } + +quit: + LDAP_TRACE (("Received %d entries\n", num)); + if (rc == LDAP_SIZELIMIT_EXCEEDED) + infof(data, "There are more than %d entries\n", num); + if (ludp) + (*ldap_free_urldesc)(ludp); + if (server) + (*ldap_unbind_s)(server); + + DynaClose(); + + /* no data to transfer */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + conn->bits.close = TRUE; + + return status; +} + +#ifdef DEBUG_LDAP +static void _ldap_trace (const char *fmt, ...) +{ + static int do_trace = -1; + va_list args; + + if (do_trace == -1) { + const char *env = getenv("CURL_TRACE"); + do_trace = (env && atoi(env) > 0); + } + if (!do_trace) + return; + + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); +} +#endif + +#ifdef WIN32 +/* + * Return scope-value for a scope-string. + */ +static int str2scope (const char *p) +{ + if (!stricmp(p, "one")) + return LDAP_SCOPE_ONELEVEL; + if (!stricmp(p, "onetree")) + return LDAP_SCOPE_ONELEVEL; + if (!stricmp(p, "base")) + return LDAP_SCOPE_BASE; + if (!stricmp(p, "sub")) + return LDAP_SCOPE_SUBTREE; + if (!stricmp( p, "subtree")) + return LDAP_SCOPE_SUBTREE; + return (-1); +} + +/* + * Split 'str' into strings separated by commas. + * Note: res[] points into 'str'. + */ +static char **split_str (char *str) +{ + char **res, *lasts, *s; + int i; + + for (i = 2, s = strchr(str,','); s; i++) + s = strchr(++s,','); + + res = calloc(i, sizeof(char*)); + if (!res) + return NULL; + + for (i = 0, s = strtok_r(str, ",", &lasts); s; + s = strtok_r(NULL, ",", &lasts), i++) + res[i] = s; + return res; +} + +/* + * Unescape the LDAP-URL components + */ +static bool unescape_elements (void *data, LDAPURLDesc *ludp) +{ + int i; + + if (ludp->lud_filter) { + ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL); + if (!ludp->lud_filter) + return (FALSE); + } + + for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { + ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL); + if (!ludp->lud_attrs[i]) + return (FALSE); + } + + for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) { + ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL); + if (!ludp->lud_exts[i]) + return (FALSE); + } + + if (ludp->lud_dn) { + char *dn = ludp->lud_dn; + char *new_dn = curl_easy_unescape(data, dn, 0, NULL); + + free(dn); + ludp->lud_dn = new_dn; + if (!new_dn) + return (FALSE); + } + return (TRUE); +} + +/* + * Break apart the pieces of an LDAP URL. + * Syntax: + * ldap://:/???? + * + * already known from 'conn->host.name'. + * already known from 'conn->remote_port'. + * extract the rest from 'conn->data->reqdata.path+1'. All fields are optional. + * e.g. + * ldap://:/??? + * yields ludp->lud_dn = "". + * + * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915 + */ +static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) +{ + char *p, *q; + int i; + + if (!conn->data || + !conn->data->reqdata.path || + conn->data->reqdata.path[0] != '/' || + !checkprefix(conn->protostr, conn->data->change.url)) + return LDAP_INVALID_SYNTAX; + + ludp->lud_scope = LDAP_SCOPE_BASE; + ludp->lud_port = conn->remote_port; + ludp->lud_host = conn->host.name; + + /* parse DN (Distinguished Name). + */ + ludp->lud_dn = strdup(conn->data->reqdata.path+1); + if (!ludp->lud_dn) + return LDAP_NO_MEMORY; + + p = strchr(ludp->lud_dn, '?'); + LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : + strlen(ludp->lud_dn), ludp->lud_dn)); + + if (!p) + goto success; + + *p++ = '\0'; + + /* parse attributes. skip "??". + */ + q = strchr(p, '?'); + if (q) + *q++ = '\0'; + + if (*p && *p != '?') { + ludp->lud_attrs = split_str(p); + if (!ludp->lud_attrs) + return LDAP_NO_MEMORY; + + for (i = 0; ludp->lud_attrs[i]; i++) + LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); + } + + p = q; + if (!p) + goto success; + + /* parse scope. skip "??" + */ + q = strchr(p, '?'); + if (q) + *q++ = '\0'; + + if (*p && *p != '?') { + ludp->lud_scope = str2scope(p); + if (ludp->lud_scope == -1) + return LDAP_INVALID_SYNTAX; + LDAP_TRACE (("scope %d\n", ludp->lud_scope)); + } + + p = q; + if (!p) + goto success; + + /* parse filter + */ + q = strchr(p, '?'); + if (q) + *q++ = '\0'; + if (!*p) + return LDAP_INVALID_SYNTAX; + + ludp->lud_filter = p; + LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); + + p = q; + if (!p) + goto success; + + /* parse extensions + */ + ludp->lud_exts = split_str(p); + if (!ludp->lud_exts) + return LDAP_NO_MEMORY; + + for (i = 0; ludp->lud_exts[i]; i++) + LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i])); + +success: + if (!unescape_elements(conn->data, ludp)) + return LDAP_NO_MEMORY; + return LDAP_SUCCESS; +} + +static int _ldap_url_parse (const struct connectdata *conn, + LDAPURLDesc **ludpp) +{ + LDAPURLDesc *ludp = calloc(sizeof(*ludp), 1); + int rc; + + *ludpp = NULL; + if (!ludp) + return LDAP_NO_MEMORY; + + rc = _ldap_url_parse2 (conn, ludp); + if (rc != LDAP_SUCCESS) { + _ldap_free_urldesc(ludp); + ludp = NULL; + } + *ludpp = ludp; + return (rc); +} + +static void _ldap_free_urldesc (LDAPURLDesc *ludp) +{ + int i; + + if (!ludp) + return; + + if (ludp->lud_dn) + free(ludp->lud_dn); + + if (ludp->lud_filter) + free(ludp->lud_filter); + + if (ludp->lud_attrs) { + for (i = 0; ludp->lud_attrs[i]; i++) + free(ludp->lud_attrs[i]); + free(ludp->lud_attrs); + } + + if (ludp->lud_exts) { + for (i = 0; ludp->lud_exts[i]; i++) + free(ludp->lud_exts[i]); + free(ludp->lud_exts); + } + free (ludp); +} +#endif /* WIN32 */ +#endif /* CURL_DISABLE_LDAP */ diff --git a/Utilities/cmcurl/lib/ldap.h b/Utilities/cmcurl/lib/ldap.h new file mode 100644 index 0000000..b2d4f39 --- /dev/null +++ b/Utilities/cmcurl/lib/ldap.h @@ -0,0 +1,29 @@ +#ifndef __LDAP_H +#define __LDAP_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_LDAP +CURLcode Curl_ldap(struct connectdata *conn, bool *done); +#endif +#endif /* __LDAP_H */ diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c new file mode 100644 index 0000000..921d1d1 --- /dev/null +++ b/Utilities/cmcurl/lib/llist.c @@ -0,0 +1,138 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#include "llist.h" +#include "memory.h" + +/* this must be the last include file */ +#include "memdebug.h" + +void +Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor) +{ + l->size = 0; + l->dtor = dtor; + l->head = NULL; + l->tail = NULL; +} + +struct curl_llist * +Curl_llist_alloc(curl_llist_dtor dtor) +{ + struct curl_llist *list; + + list = (struct curl_llist *)malloc(sizeof(struct curl_llist)); + if(NULL == list) + return NULL; + + Curl_llist_init(list, dtor); + + return list; +} + +/* + * Curl_llist_insert_next() returns 1 on success and 0 on failure. + */ +int +Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, + const void *p) +{ + struct curl_llist_element *ne = + (struct curl_llist_element *) malloc(sizeof(struct curl_llist_element)); + if(!ne) + return 0; + + ne->ptr = (void *) p; + if (list->size == 0) { + list->head = ne; + list->head->prev = NULL; + list->head->next = NULL; + list->tail = ne; + } + else { + ne->next = e->next; + ne->prev = e; + if (e->next) { + e->next->prev = ne; + } + else { + list->tail = ne; + } + e->next = ne; + } + + ++list->size; + + return 1; +} + +int +Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, + void *user) +{ + if (e == NULL || list->size == 0) + return 1; + + if (e == list->head) { + list->head = e->next; + + if (list->head == NULL) + list->tail = NULL; + else + e->next->prev = NULL; + } else { + e->prev->next = e->next; + if (!e->next) + list->tail = e->prev; + else + e->next->prev = e->prev; + } + + list->dtor(user, e->ptr); + free(e); + --list->size; + + return 1; +} + +void +Curl_llist_destroy(struct curl_llist *list, void *user) +{ + if(list) { + while (list->size > 0) + Curl_llist_remove(list, list->tail, user); + + free(list); + } +} + +size_t +Curl_llist_count(struct curl_llist *list) +{ + return list->size; +} diff --git a/Utilities/cmcurl/lib/llist.h b/Utilities/cmcurl/lib/llist.h new file mode 100644 index 0000000..5c7a8a0 --- /dev/null +++ b/Utilities/cmcurl/lib/llist.h @@ -0,0 +1,60 @@ +#ifndef __LLIST_H +#define __LLIST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include + +typedef void (*curl_llist_dtor)(void *, void *); + +struct curl_llist_element { + void *ptr; + + struct curl_llist_element *prev; + struct curl_llist_element *next; +}; + +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); +struct curl_llist *Curl_llist_alloc(curl_llist_dtor); +int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *, + const void *); +int Curl_llist_insert_prev(struct curl_llist *, struct curl_llist_element *, + const void *); +int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, + void *); +int Curl_llist_remove_next(struct curl_llist *, struct curl_llist_element *, + void *); +size_t Curl_llist_count(struct curl_llist *); +void Curl_llist_destroy(struct curl_llist *, void *); + +#endif diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c new file mode 100644 index 0000000..4cfb073 --- /dev/null +++ b/Utilities/cmcurl/lib/md5.c @@ -0,0 +1,352 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_CRYPTO_AUTH + +#if !defined(USE_SSLEAY) || !defined(USE_OPENSSL) +/* This code segment is only used if OpenSSL is not provided, as if it is + we use the MD5-function provided there instead. No good duplicating + code! */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include + +/* UINT4 defines a four byte word */ +typedef unsigned int UINT4; + +/* MD5 context. */ +struct md5_ctx { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +}; + +typedef struct md5_ctx MD5_CTX; + +static void MD5_Init(struct md5_ctx *); +static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int); +static void MD5_Final(unsigned char [16], struct md5_ctx *); + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(UINT4 [4], const unsigned char [64]); +static void Encode(unsigned char *, UINT4 *, unsigned int); +static void Decode(UINT4 *, const unsigned char *, unsigned int); + +static const unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +static void MD5_Init(struct md5_ctx *context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +static void MD5_Update (struct md5_ctx *context, /* context */ + const unsigned char *input, /* input block */ + unsigned int inputLen) /* length of input block */ +{ + unsigned int i, bufindex, partLen; + + /* Compute number of bytes mod 64 */ + bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - bufindex; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + memcpy((void *)&context->buffer[bufindex], (void *)input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform(context->state, &input[i]); + + bufindex = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy((void *)&context->buffer[bufindex], (void *)&input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. +*/ +static void MD5_Final(unsigned char digest[16], /* message digest */ + struct md5_ctx *context) /* context */ +{ + unsigned char bits[8]; + unsigned int count, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + count = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (count < 56) ? (56 - count) : (120 - count); + MD5_Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5_Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset ((void *)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. */ +static void MD5Transform(UINT4 state[4], + const unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset((void *)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (unsigned char *output, + UINT4 *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. +*/ +static void Decode (UINT4 *output, + const unsigned char *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +#else +/* If OpenSSL is present */ +#include +#include +#endif + +#include "md5.h" + +void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */ + const unsigned char *input) +{ + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, input, (unsigned int)strlen((char *)input)); + MD5_Final(outbuffer, &ctx); +} + +#endif diff --git a/Utilities/cmcurl/lib/md5.h b/Utilities/cmcurl/lib/md5.h new file mode 100644 index 0000000..63cc70e --- /dev/null +++ b/Utilities/cmcurl/lib/md5.h @@ -0,0 +1,29 @@ +#ifndef __MD5_H +#define __MD5_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +void Curl_md5it(unsigned char *output, + const unsigned char *input); + +#endif diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c new file mode 100644 index 0000000..a8cca44 --- /dev/null +++ b/Utilities/cmcurl/lib/memdebug.c @@ -0,0 +1,298 @@ +#ifdef CURLDEBUG +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#define _MPRINTF_REPLACE +#include +#include "urldata.h" +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ +#include "memory.h" +#include "memdebug.h" + +struct memdebug { + size_t size; + double mem[1]; + /* I'm hoping this is the thing with the strictest alignment + * requirements. That also means we waste some space :-( */ +}; + +/* + * Note that these debug functions are very simple and they are meant to + * remain so. For advanced analysis, record a log file and write perl scripts + * to analyze them! + * + * Don't use these with multithreaded test programs! + */ + +#define logfile curl_debuglogfile +FILE *curl_debuglogfile = NULL; +static bool memlimit = FALSE; /* enable memory limit */ +static long memsize = 0; /* set number of mallocs allowed */ + +/* this sets the log file name */ +void curl_memdebug(const char *logname) +{ + if (!logfile) { + if(logname) + logfile = fopen(logname, "w"); + else + logfile = stderr; + } +} + +/* This function sets the number of malloc() calls that should return + successfully! */ +void curl_memlimit(long limit) +{ + if (!memlimit) { + memlimit = TRUE; + memsize = limit; + } +} + +/* 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 + should not be made */ + if(memlimit && source) { + if(!memsize) { + if(logfile && source) + fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n", + source, line, func); + if(source) + fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", + source, line, func); + errno = ENOMEM; + return TRUE; /* RETURN ERROR! */ + } + else + memsize--; /* countdown */ + + /* log the countdown */ + if(logfile && source) + fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n", + source, line, memsize); + + } + + return FALSE; /* allow this */ +} + +void *curl_domalloc(size_t wantedsize, int line, const char *source) +{ + struct memdebug *mem; + size_t size; + + if(countcheck("malloc", line, source)) + return NULL; + + /* alloc at least 64 bytes */ + size = sizeof(struct memdebug)+wantedsize; + + mem=(struct memdebug *)(Curl_cmalloc)(size); + if(mem) { + /* fill memory with junk */ + memset(mem->mem, 0xA5, wantedsize); + mem->size = wantedsize; + } + + if(logfile && source) + fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n", + source, line, wantedsize, mem ? mem->mem : 0); + return (mem ? mem->mem : NULL); +} + +void *curl_docalloc(size_t wanted_elements, size_t wanted_size, + int line, const char *source) +{ + struct memdebug *mem; + size_t size, user_size; + + if(countcheck("calloc", line, source)) + return NULL; + + /* alloc at least 64 bytes */ + user_size = wanted_size * wanted_elements; + size = sizeof(struct memdebug) + user_size; + + mem = (struct memdebug *)(Curl_cmalloc)(size); + if(mem) { + /* fill memory with zeroes */ + memset(mem->mem, 0, user_size); + mem->size = user_size; + } + + if(logfile && source) + fprintf(logfile, "MEM %s:%d calloc(%u,%u) = %p\n", + source, line, wanted_elements, wanted_size, mem ? mem->mem : 0); + return (mem ? mem->mem : NULL); +} + +char *curl_dostrdup(const char *str, int line, const char *source) +{ + char *mem; + size_t len; + + curlassert(str != NULL); + + if(countcheck("strdup", line, source)) + return NULL; + + len=strlen(str)+1; + + mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */ + if (mem) + memcpy(mem, str, len); + + if(logfile) + fprintf(logfile, "MEM %s:%d strdup(%p) (%zd) = %p\n", + source, line, str, len, mem); + + return mem; +} + +/* We provide a realloc() that accepts a NULL as pointer, which then + performs a malloc(). In order to work with ares. */ +void *curl_dorealloc(void *ptr, size_t wantedsize, + int line, const char *source) +{ + struct memdebug *mem=NULL; + + size_t size = sizeof(struct memdebug)+wantedsize; + + if(countcheck("realloc", line, source)) + return NULL; + + if(ptr) + mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem)); + + mem=(struct memdebug *)(Curl_crealloc)(mem, size); + if(logfile) + fprintf(logfile, "MEM %s:%d realloc(%p, %zd) = %p\n", + source, line, ptr, wantedsize, mem?mem->mem:NULL); + + if(mem) { + mem->size = wantedsize; + return mem->mem; + } + + return NULL; +} + +void curl_dofree(void *ptr, int line, const char *source) +{ + struct memdebug *mem; + + curlassert(ptr != NULL); + + mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem)); + + /* destroy */ + memset(mem->mem, 0x13, mem->size); + + /* free for real */ + (Curl_cfree)(mem); + + if(logfile) + fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr); +} + +int curl_socket(int domain, int type, int protocol, int line, + const char *source) +{ + int sockfd=(socket)(domain, type, protocol); + if(logfile && (sockfd!=-1)) + fprintf(logfile, "FD %s:%d socket() = %d\n", + source, line, sockfd); + return sockfd; +} + +int curl_accept(int s, void *saddr, void *saddrlen, + int line, const char *source) +{ + struct sockaddr *addr = (struct sockaddr *)saddr; + socklen_t *addrlen = (socklen_t *)saddrlen; + int sockfd=(accept)(s, addr, addrlen); + if(logfile) + fprintf(logfile, "FD %s:%d accept() = %d\n", + source, line, sockfd); + return sockfd; +} + +/* this is our own defined way to close sockets on *ALL* platforms */ +int curl_sclose(int sockfd, int line, const char *source) +{ + int res=sclose(sockfd); + if(logfile) + fprintf(logfile, "FD %s:%d sclose(%d)\n", + source, line, sockfd); + return res; +} + +FILE *curl_fopen(const char *file, const char *mode, + int line, const char *source) +{ + FILE *res=(fopen)(file, mode); + if(logfile) + fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", + source, line, file, mode, res); + return res; +} + +int curl_fclose(FILE *file, int line, const char *source) +{ + int res; + + curlassert(file != NULL); + + res=(fclose)(file); + if(logfile) + fprintf(logfile, "FILE %s:%d fclose(%p)\n", + source, line, file); + return res; +} +#else +#ifdef VMS +int VOID_VAR_MEMDEBUG; +#else +/* we provide a fake do-nothing function here to avoid compiler warnings */ +void curl_memdebug(void) {} +#endif /* VMS */ +#endif /* CURLDEBUG */ diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h new file mode 100644 index 0000000..a4ce7e5 --- /dev/null +++ b/Utilities/cmcurl/lib/memdebug.h @@ -0,0 +1,125 @@ +#ifdef CURLDEBUG +#ifndef _CURL_MEDEBUG_H +#define _CURL_MEDEBUG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * CAUTION: this header is designed to work when included by the app-side + * as well as the library. Do not mix with library internals! + */ + +#include "setup.h" + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_MEMORY_H +#include +#endif + +#define logfile curl_debuglogfile + +extern FILE *logfile; + +/* memory functions */ +CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source); +CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, const char *source); +CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, const char *source); +CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source); +CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source); +CURL_EXTERN void curl_memdebug(const char *logname); +CURL_EXTERN void curl_memlimit(long limit); + +/* file descriptor manipulators */ +CURL_EXTERN int curl_socket(int domain, int type, int protocol, int line , const char *); +CURL_EXTERN int curl_sclose(int sockfd, int, const char *source); +CURL_EXTERN int curl_accept(int s, void *addr, void *addrlen, + int line, const char *source); + +/* FILE functions */ +CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line, + const char *source); +CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); + +#ifndef MEMDEBUG_NODEFINES + +/* Set this symbol on the command-line, recompile all lib-sources */ +#undef strdup +#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__) +#define malloc(size) curl_domalloc(size, __LINE__, __FILE__) +#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__) +#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__) +#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__) + +#define socket(domain,type,protocol)\ + curl_socket(domain,type,protocol,__LINE__,__FILE__) +#undef accept /* for those with accept as a macro */ +#define accept(sock,addr,len)\ + curl_accept(sock,addr,len,__LINE__,__FILE__) + +#if defined(getaddrinfo) && defined(__osf__) +/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define + our macro as for other platforms. Instead, we redefine the new name they + define getaddrinfo to become! */ +#define ogetaddrinfo(host,serv,hint,res) \ + curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) +#else +#undef getaddrinfo +#define getaddrinfo(host,serv,hint,res) \ + curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) +#endif + +#ifdef HAVE_GETNAMEINFO +#undef getnameinfo +#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \ + curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \ + __FILE__) +#endif + +#undef freeaddrinfo +#define freeaddrinfo(data) \ + curl_dofreeaddrinfo(data,__LINE__,__FILE__) + +/* sclose is probably already defined, redefine it! */ +#undef sclose +#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__) +/* ares-adjusted define: */ +#undef closesocket +#define closesocket(sockfd) curl_sclose(sockfd,__LINE__,__FILE__) + +#undef fopen +#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__) +#define fclose(file) curl_fclose(file,__LINE__,__FILE__) + +#endif /* MEMDEBUG_NODEFINES */ + +#endif /* _CURL_MEDEBUG_H */ +#endif /* CURLDEBUG */ diff --git a/Utilities/cmcurl/lib/memory.h b/Utilities/cmcurl/lib/memory.h new file mode 100644 index 0000000..076d20a --- /dev/null +++ b/Utilities/cmcurl/lib/memory.h @@ -0,0 +1,50 @@ +#ifndef _CURL_MEMORY_H +#define _CURL_MEMORY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include /* for the typedefs */ + +extern curl_malloc_callback Curl_cmalloc; +extern curl_free_callback Curl_cfree; +extern curl_realloc_callback Curl_crealloc; +extern curl_strdup_callback Curl_cstrdup; +extern curl_calloc_callback Curl_ccalloc; + +#ifndef CURLDEBUG +/* Only do this define-mania if we're not using the memdebug system, as that + has preference on this magic. */ +#undef strdup +#define strdup(ptr) Curl_cstrdup(ptr) +#undef malloc +#define malloc(size) Curl_cmalloc(size) +#undef calloc +#define calloc(nbelem,size) Curl_ccalloc(nbelem, size) +#undef realloc +#define realloc(ptr,size) Curl_crealloc(ptr, size) +#undef free +#define free(ptr) Curl_cfree(ptr) + +#endif + +#endif /* _CURL_MEMORY_H */ diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c new file mode 100644 index 0000000..8b2f3d0 --- /dev/null +++ b/Utilities/cmcurl/lib/mprintf.c @@ -0,0 +1,1218 @@ +/**************************************************************************** + * + * $Id$ + * + ************************************************************************* + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + * Purpose: + * A merge of Bjorn Reese's format() function and Daniel's dsprintf() + * 1.0. A full blooded printf() clone with full support for $ + * 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 http://daniel.haxx.se/trio/ + */ + + +#include "setup.h" +#include +#include +#include +#include +#include +#include + +#if defined(DJGPP) && (DJGPP_MINOR < 4) +#undef _MPRINTF_REPLACE /* don't use x_was_used() here */ +#endif + +#include + +#ifndef SIZEOF_SIZE_T +/* default to 4 bytes for size_t unless defined in the config.h */ +#define SIZEOF_SIZE_T 4 +#endif + +#ifdef DPRINTF_DEBUG +#define HAVE_LONGLONG +#define LONG_LONG long long +#define ENABLE_64BIT +#endif + +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ +#define MAX_PARAMETERS 128 /* lame static limit */ + +#undef TRUE +#undef FALSE +#undef BOOL +#ifdef __cplusplus +# define TRUE true +# define FALSE false +# define BOOL bool +#else +# define TRUE ((char)(1 == 1)) +# define FALSE ((char)(0 == 1)) +# define BOOL char +#endif + +#ifdef _AMIGASF +# undef FORMAT_INT +#endif + +/* Lower-case digits. */ +static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +/* Upper-case digits. */ +static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#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_INT, + FORMAT_INTPTR, + FORMAT_LONG, + FORMAT_LONGLONG, + FORMAT_DOUBLE, + FORMAT_LONGDOUBLE, + FORMAT_WIDTH /* For internal use */ +} FormatType; + +/* convertion and display flags */ +enum { + FLAGS_NEW = 0, + FLAGS_SPACE = 1<<0, + FLAGS_SHOWSIGN = 1<<1, + FLAGS_LEFT = 1<<2, + FLAGS_ALT = 1<<3, + FLAGS_SHORT = 1<<4, + FLAGS_LONG = 1<<5, + FLAGS_LONGLONG = 1<<6, + FLAGS_LONGDOUBLE = 1<<7, + FLAGS_PAD_NIL = 1<<8, + FLAGS_UNSIGNED = 1<<9, + FLAGS_OCTAL = 1<<10, + FLAGS_HEX = 1<<11, + FLAGS_UPPER = 1<<12, + FLAGS_WIDTH = 1<<13, /* '*' or '*$' used */ + FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ + FLAGS_PREC = 1<<15, /* precision was specified */ + 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 */ +}; + +typedef struct { + FormatType type; + int flags; + long width; /* width OR width parameter number */ + long precision; /* precision OR precision parameter number */ + union { + char *str; + void *ptr; + long num; +#ifdef ENABLE_64BIT + LONG_LONG lnum; +#endif + double dnum; + } data; +} va_stack_t; + +struct nsprintf { + char *buffer; + size_t length; + size_t max; +}; + +struct asprintf { + char *buffer; /* allocated buffer */ + size_t len; /* length of string */ + size_t alloc; /* length of alloc */ + bool fail; /* TRUE if an alloc has failed and thus the output is not + the complete data */ +}; + +int curl_msprintf(char *buffer, const char *format, ...); + +static long dprintf_DollarString(char *input, char **end) +{ + int number=0; + while(ISDIGIT(*input)) { + number *= 10; + number += *input-'0'; + input++; + } + if(number && ('$'==*input++)) { + *end = input; + return number; + } + return 0; +} + +static BOOL dprintf_IsQualifierNoDollar(char c) +{ + switch (c) { + 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': + return TRUE; + default: + return FALSE; + } +} + +#ifdef DPRINTF_DEBUG2 +int dprintf_Pass1Report(va_stack_t *vto, int max) +{ + int i; + char buffer[128]; + int bit; + int flags; + + for(i=0; i 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)) { + switch (*fmt++) { + case ' ': + flags |= FLAGS_SPACE; + break; + case '+': + flags |= FLAGS_SHOWSIGN; + break; + case '-': + flags |= FLAGS_LEFT; + flags &= ~FLAGS_PAD_NIL; + break; + case '#': + flags |= FLAGS_ALT; + break; + case '.': + flags |= FLAGS_PREC; + if ('*' == *fmt) { + /* The precision is picked from a specified parameter */ + + flags |= FLAGS_PRECPARAM; + fmt++; + param_num++; + + i = dprintf_DollarString(fmt, &fmt); + if (i) + precision = i; + else + precision = param_num; + + if (precision > max_param) + max_param = precision; + } + else { + flags |= FLAGS_PREC; + precision = strtol(fmt, &fmt, 10); + } + break; + case 'h': + flags |= FLAGS_SHORT; + break; + case 'l': + if (flags & FLAGS_LONG) + flags |= FLAGS_LONGLONG; + else + flags |= FLAGS_LONG; + break; + case 'L': + flags |= FLAGS_LONGDOUBLE; + break; + case 'q': + flags |= FLAGS_LONGLONG; + break; + case 'z': + /* the code below generates a warning if -Wunreachable-code is + used */ +#if SIZEOF_SIZE_T>4 + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; + case 'O': +#if SIZEOF_CURL_OFF_T > 4 + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; + case '0': + if (!(flags & FLAGS_LEFT)) + flags |= FLAGS_PAD_NIL; + /* FALLTHROUGH */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + flags |= FLAGS_WIDTH; + width = strtol(fmt-1, &fmt, 10); + break; + case '*': /* Special case */ + flags |= FLAGS_WIDTHPARAM; + param_num++; + + i = dprintf_DollarString(fmt, &fmt); + if(i) + width = i; + else + width = param_num; + if(width > max_param) + max_param=width; + break; + default: + break; + } + } /* switch */ + + /* Handle the specifier */ + + i = this_param - 1; + + switch (*fmt) { + case 'S': + flags |= FLAGS_ALT; + /* FALLTHROUGH */ + case 's': + vto[i].type = FORMAT_STRING; + break; + case 'n': + vto[i].type = FORMAT_INTPTR; + break; + case 'p': + vto[i].type = FORMAT_PTR; + break; + case 'd': case 'i': + vto[i].type = FORMAT_INT; + break; + case 'u': + vto[i].type = FORMAT_INT; + flags |= FLAGS_UNSIGNED; + break; + case 'o': + vto[i].type = FORMAT_INT; + flags |= FLAGS_OCTAL; + break; + case 'x': + vto[i].type = FORMAT_INT; + flags |= FLAGS_HEX; + break; + case 'X': + vto[i].type = FORMAT_INT; + flags |= FLAGS_HEX|FLAGS_UPPER; + break; + case 'c': + vto[i].type = FORMAT_INT; + flags |= FLAGS_CHAR; + break; + case 'f': + vto[i].type = FORMAT_DOUBLE; + break; + case 'e': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE; + break; + case 'E': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE|FLAGS_UPPER; + break; + case 'g': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG; + break; + case 'G': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG|FLAGS_UPPER; + break; + default: + vto[i].type = FORMAT_UNKNOWN; + break; + } /* switch */ + + vto[i].flags = flags; + vto[i].width = width; + vto[i].precision = precision; + + if (flags & FLAGS_WIDTHPARAM) { + /* we have the width specified from a parameter, so we make that + parameter's info setup properly */ + vto[i].width = width - 1; + i = width - 1; + vto[i].type = FORMAT_WIDTH; + vto[i].flags = FLAGS_NEW; + vto[i].precision = vto[i].width = 0; /* can't use width or precision + of width! */ + } + if (flags & FLAGS_PRECPARAM) { + /* we have the precision specified from a parameter, so we make that + parameter's info setup properly */ + vto[i].precision = precision - 1; + i = precision - 1; + vto[i].type = FORMAT_WIDTH; + vto[i].flags = FLAGS_NEW; + vto[i].precision = vto[i].width = 0; /* can't use width or precision + of width! */ + } + *endpos++ = fmt + 1; /* end of this sequence */ + } + } + +#ifdef DPRINTF_DEBUG2 + dprintf_Pass1Report(vto, max_param); +#endif + + /* Read the arg list parameters into our data list */ + for (i=0; i$ 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(p->flags & FLAGS_WIDTHPARAM) + width = vto[p->width].data.num; + else + width = p->width; + + /* pick up the specified precision */ + if(p->flags & FLAGS_PRECPARAM) + prec = vto[p->precision].data.num; + else if(p->flags & FLAGS_PREC) + prec = p->precision; + else + prec = -1; + + alt = (p->flags & FLAGS_ALT)?TRUE:FALSE; + + switch (p->type) { + case FORMAT_INT: + num = p->data.num; + if(p->flags & FLAGS_CHAR) { + /* Character. */ + if (!(p->flags & FLAGS_LEFT)) + while (--width > 0) + OUTCHAR(' '); + OUTCHAR((char) num); + if (p->flags & FLAGS_LEFT) + while (--width > 0) + OUTCHAR(' '); + break; + } + if(p->flags & FLAGS_UNSIGNED) { + /* Decimal unsigned integer. */ + base = 10; + goto unsigned_number; + } + if(p->flags & FLAGS_OCTAL) { + /* Octal unsigned integer. */ + base = 8; + goto unsigned_number; + } + if(p->flags & FLAGS_HEX) { + /* Hexadecimal unsigned integer. */ + + digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + base = 16; + goto unsigned_number; + } + + /* Decimal integer. */ + base = 10; + +#ifdef ENABLE_64BIT + if(p->flags & FLAGS_LONGLONG) { + /* long long */ + is_neg = p->data.lnum < 0; + num = is_neg ? (- p->data.lnum) : p->data.lnum; + } + else +#endif + { + signed_num = (long) num; + is_neg = signed_num < 0; + num = is_neg ? (- signed_num) : signed_num; + } + goto number; + + unsigned_number: + /* Unsigned number of base BASE. */ + is_neg = 0; + + number: + /* Number of base BASE. */ + { + char *workend = &work[sizeof(work) - 1]; + char *w; + + /* Supply a default precision if none was given. */ + if (prec == -1) + prec = 1; + + /* Put the number in WORK. */ + w = workend; + while (num > 0) { + *w-- = digits[num % base]; + num /= base; + } + width -= (long)(workend - w); + prec -= (long)(workend - w); + + if (alt && base == 8 && prec <= 0) { + *w-- = '0'; + --width; + } + + if (prec > 0) { + width -= prec; + while (prec-- > 0) + *w-- = '0'; + } + + if (alt && base == 16) + width -= 2; + + if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) + --width; + + if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) + while (width-- > 0) + OUTCHAR(' '); + + if (is_neg) + OUTCHAR('-'); + else if (p->flags & FLAGS_SHOWSIGN) + OUTCHAR('+'); + else if (p->flags & FLAGS_SPACE) + OUTCHAR(' '); + + if (alt && base == 16) { + OUTCHAR('0'); + if(p->flags & FLAGS_UPPER) + OUTCHAR('X'); + else + OUTCHAR('x'); + } + + if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) + while (width-- > 0) + OUTCHAR('0'); + + /* Write the number. */ + while (++w <= workend) { + OUTCHAR(*w); + } + + if (p->flags & FLAGS_LEFT) + while (width-- > 0) + OUTCHAR(' '); + } + break; + + case FORMAT_STRING: + /* String. */ + { + static const char null[] = "(nil)"; + const char *str; + size_t len; + + str = (char *) p->data.str; + if ( str == NULL) { + /* 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 + len = strlen(str); + + if (prec != -1 && (size_t) prec < len) + len = prec; + width -= (long)len; + + if (p->flags & FLAGS_ALT) + OUTCHAR('"'); + + if (!(p->flags&FLAGS_LEFT)) + while (width-- > 0) + OUTCHAR(' '); + + while (len-- > 0) + OUTCHAR(*str++); + if (p->flags&FLAGS_LEFT) + while (width-- > 0) + OUTCHAR(' '); + + if (p->flags & FLAGS_ALT) + OUTCHAR('"'); + } + break; + + case FORMAT_PTR: + /* Generic pointer. */ + { + void *ptr; + ptr = (void *) p->data.ptr; + if (ptr != NULL) { + /* If the pointer is not NULL, write it as a %#x spec. */ + base = 16; + digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + 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 -= 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; + 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 = vto[p->width].data.num; + + prec = -1; + if (p->flags & FLAGS_PREC) + prec = p->precision; + else if (p->flags & FLAGS_PRECPARAM) + prec = vto[p->precision].data.num; + + if (p->flags & FLAGS_LEFT) + strcat(formatbuf, "-"); + if (p->flags & FLAGS_SHOWSIGN) + strcat(formatbuf, "+"); + if (p->flags & FLAGS_SPACE) + strcat(formatbuf, " "); + if (p->flags & FLAGS_ALT) + strcat(formatbuf, "#"); + + fptr=&formatbuf[strlen(formatbuf)]; + + if(width >= 0) { + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, "%ld", width); + fptr += len; + left -= len; + } + if(prec >= 0) { + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, ".%ld", prec); + fptr += len; + left -= len; + } + if (p->flags & FLAGS_LONG) + *fptr++ = 'l'; + + if (p->flags & FLAGS_FLOATE) + *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e'; + else if (p->flags & FLAGS_FLOATG) + *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g'; + else + *fptr++ = 'f'; + + *fptr = 0; /* and a final zero termination */ + + /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number + of output characters */ + (sprintf)(work, formatbuf, p->data.dnum); + + for(fptr=work; *fptr; fptr++) + OUTCHAR(*fptr); + } + break; + + case FORMAT_INTPTR: + /* Answer the count of characters written. */ +#ifdef ENABLE_64BIT + if (p->flags & FLAGS_LONGLONG) + *(LONG_LONG *) p->data.ptr = (LONG_LONG)done; + else +#endif + 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 *) p->data.ptr = (short)done; + break; + + default: + break; + } + f = *end++; /* goto end of %-code */ + + } + return done; +} + +/* fputc() look-alike */ +static int addbyter(int output, FILE *data) +{ + struct nsprintf *infop=(struct nsprintf *)data; + unsigned char outc = (unsigned char)output; + + if(infop->length < infop->max) { + /* 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 outc; /* fputc() returns like this on success */ + } + return -1; +} + +int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, + va_list ap_save) +{ + int retcode; + struct nsprintf info; + + info.buffer = buffer; + info.length = 0; + info.max = maxlength; + + retcode = dprintf_formatf(&info, addbyter, format, ap_save); + if(info.max) { + /* we terminate this with a zero byte */ + if(info.max == info.length) + /* we're at maximum, scrap the last letter */ + info.buffer[-1] = 0; + else + info.buffer[0] = 0; + } + return retcode; +} + +int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); + va_end(ap_save); + return retcode; +} + +/* fputc() look-alike */ +static int alloc_addbyter(int output, FILE *data) +{ + struct asprintf *infop=(struct asprintf *)data; + unsigned char outc = (unsigned char)output; + + if(!infop->buffer) { + infop->buffer=(char *)malloc(32); + if(!infop->buffer) { + infop->fail = TRUE; + return -1; /* fail */ + } + infop->alloc = 32; + infop->len =0; + } + else if(infop->len+1 >= infop->alloc) { + char *newptr; + + newptr = (char *)realloc(infop->buffer, infop->alloc*2); + + if(!newptr) { + infop->fail = TRUE; + return -1; + } + infop->buffer = newptr; + infop->alloc *= 2; + } + + infop->buffer[ infop->len ] = outc; + + infop->len++; + + return outc; /* fputc() returns like this on success */ +} + +char *curl_maprintf(const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + struct asprintf info; + + info.buffer = NULL; + info.len = 0; + info.alloc = 0; + info.fail = FALSE; + + va_start(ap_save, format); + retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); + va_end(ap_save); + if((-1 == retcode) || info.fail) { + if(info.alloc) + free(info.buffer); + return NULL; + } + if(info.alloc) { + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + return info.buffer; + } + else + return strdup(""); +} + +char *curl_mvaprintf(const char *format, va_list ap_save) +{ + int retcode; + struct asprintf info; + + info.buffer = NULL; + info.len = 0; + info.alloc = 0; + info.fail = FALSE; + + retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); + if((-1 == retcode) || info.fail) { + if(info.alloc) + free(info.buffer); + return NULL; + } + + if(info.alloc) { + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + return info.buffer; + } + else + return strdup(""); +} + +static int storebuffer(int output, FILE *data) +{ + char **buffer = (char **)data; + unsigned char outc = (unsigned char)output; + **buffer = outc; + (*buffer)++; + return outc; /* act like fputc() ! */ +} + +int curl_msprintf(char *buffer, const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + va_start(ap_save, format); + retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + va_end(ap_save); + *buffer=0; /* we terminate this with a zero byte */ + return retcode; +} + +int curl_mprintf(const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + + retcode = dprintf_formatf(stdout, fputc, format, ap_save); + va_end(ap_save); + return retcode; +} + +int curl_mfprintf(FILE *whereto, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + 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; + 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 dprintf_formatf(stdout, fputc, format, ap_save); +} + +int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) +{ + return dprintf_formatf(whereto, fputc, format, ap_save); +} + +#ifdef DPRINTF_DEBUG +int main() +{ + char buffer[129]; + char *ptr; +#ifdef ENABLE_64BIT + long long one=99; + long long two=100; + long long test = 0x1000000000LL; + curl_mprintf("%lld %lld %lld\n", one, two, test); +#endif + + curl_mprintf("%3d %5d\n", 10, 1998); + + ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001); + + puts(ptr); + + memset(ptr, 55, strlen(ptr)+1); + + free(ptr); + +#if 1 + curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988); + puts(buffer); + + curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65); + + printf("%s %#08x\n", "dummy", 65); + { + double tryout = 3.14156592; + curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout); + puts(buffer); + printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout); + } +#endif + + return 0; +} + +#endif diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c new file mode 100644 index 0000000..869d568 --- /dev/null +++ b/Utilities/cmcurl/lib/multi.c @@ -0,0 +1,1988 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#include "urldata.h" +#include "transfer.h" +#include "url.h" +#include "connect.h" +#include "progress.h" +#include "memory.h" +#include "easyif.h" +#include "multiif.h" +#include "sendf.h" +#include "timeval.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +struct Curl_message { + /* the 'CURLMsg' is the part that is visible to the external user */ + struct CURLMsg extmsg; + struct Curl_message *next; +}; + +typedef enum { + CURLM_STATE_INIT, /* start in this state */ + CURLM_STATE_CONNECT, /* resolve/connect has been sent off */ + CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */ + CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */ + CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect + phase */ + CURLM_STATE_WAITDO, /* wait for our turn to send the request */ + CURLM_STATE_DO, /* start send off the request (part 1) */ + CURLM_STATE_DOING, /* sending off the request (part 1) */ + CURLM_STATE_DO_MORE, /* send off the request (part 2) */ + CURLM_STATE_DO_DONE, /* done sending off request */ + CURLM_STATE_WAITPERFORM, /* wait for our turn to read the response */ + CURLM_STATE_PERFORM, /* transfer data */ + CURLM_STATE_TOOFAST, /* wait because limit-rate exceeded */ + CURLM_STATE_DONE, /* post data transfer operation */ + CURLM_STATE_COMPLETED, /* operation complete */ + CURLM_STATE_CANCELLED, /* cancelled */ + + CURLM_STATE_LAST /* not a true state, never use this */ +} CURLMstate; + +/* we support N sockets per easy handle. Set the corresponding bit to what + action we should wait for */ +#define MAX_SOCKSPEREASYHANDLE 5 +#define GETSOCK_READABLE (0x00ff) +#define GETSOCK_WRITABLE (0xff00) + +struct closure { + struct closure *next; /* a simple one-way list of structs */ + struct SessionHandle *easy_handle; +}; + +struct Curl_one_easy { + /* first, two fields for the linked list of these */ + struct Curl_one_easy *next; + struct Curl_one_easy *prev; + + struct SessionHandle *easy_handle; /* the easy handle for this unit */ + struct connectdata *easy_conn; /* the "unit's" connection */ + + CURLMstate state; /* the handle's state */ + CURLcode result; /* previous result */ + + struct Curl_message *msg; /* A pointer to one single posted message. + Cleanup should be done on this pointer NOT on + the linked list in Curl_multi. This message + will be deleted when this handle is removed + from the multi-handle */ + int msg_num; /* number of messages left in 'msg' to return */ + + /* Array with the plain socket numbers this handle takes care of, in no + particular order. Note that all sockets are added to the sockhash, where + the state etc are also kept. This array is mostly used to detect when a + socket is to be removed from the hash. See singlesocket(). */ + curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; + int numsocks; +}; + +#define CURL_MULTI_HANDLE 0x000bab1e + +#define GOOD_MULTI_HANDLE(x) \ + ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE)) +#define GOOD_EASY_HANDLE(x) \ + (((struct SessionHandle *)x)->magic == CURLEASY_MAGIC_NUMBER) + +/* 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. */ + long type; + + /* We have a linked list with easy handles */ + struct Curl_one_easy easy; + + int num_easy; /* amount of entries in the linked list above. */ + int num_msgs; /* amount of messages in the easy handles */ + int num_alive; /* amount of easy handles that are added but have not yet + reached COMPLETE state */ + + /* callback function and user data pointer for the *socket() API */ + curl_socket_callback socket_cb; + void *socket_userp; + + /* Hostname cache */ + struct curl_hash *hostcache; + + /* timetree points to the splay-tree of time nodes to figure out expire + times of all currently set timers */ + struct Curl_tree *timetree; + + /* '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; + + /* Whether pipelining is enabled for this multi handle */ + bool pipelining_enabled; + + /* shared connection cache */ + struct conncache *connc; + + /* list of easy handles kept around for doing nice connection closures */ + struct closure *closure; + + /* timer callback and user data pointer for the *socket() API */ + curl_multi_timer_callback timer_cb; + void *timer_userp; + time_t timer_lastcall; /* the fixed time for the timeout for the previous + callback */ +}; + +static bool multi_conn_using(struct Curl_multi *multi, + struct SessionHandle *data); +static void singlesocket(struct Curl_multi *multi, + struct Curl_one_easy *easy); +static void add_closure(struct Curl_multi *multi, + struct SessionHandle *data); +static int update_timer(struct Curl_multi *multi); + +#ifdef CURLDEBUG +static const char *statename[]={ + "INIT", + "CONNECT", + "WAITRESOLVE", + "WAITCONNECT", + "PROTOCONNECT", + "WAITDO", + "DO", + "DOING", + "DO_MORE", + "DO_DONE", + "WAITPERFORM", + "PERFORM", + "TOOFAST", + "DONE", + "COMPLETED", + "CANCELLED" +}; + +void curl_multi_dump(CURLM *multi_handle); +#endif + +/* always use this function to change state, to make debugging easier */ +static void multistate(struct Curl_one_easy *easy, CURLMstate state) +{ +#ifdef CURLDEBUG + long index = -1; +#endif + CURLMstate oldstate = easy->state; + + if(oldstate == state) + /* don't bother when the new state is the same as the old state */ + return; + + easy->state = state; + +#ifdef CURLDEBUG + if(easy->state > CURLM_STATE_CONNECT && + easy->state < CURLM_STATE_COMPLETED) + index = easy->easy_conn->connectindex; + + infof(easy->easy_handle, + "STATE: %s => %s handle %p; (connection #%ld) \n", + statename[oldstate], statename[easy->state], + (char *)easy, index); +#endif + if(state == CURLM_STATE_COMPLETED) + /* changing to COMPLETED means there's one less easy handle 'alive' */ + easy->easy_handle->multi->num_alive--; +} + +/* + * We add one of these structs to the sockhash for a particular socket + */ + +struct Curl_sh_entry { + struct SessionHandle *easy; + time_t timestamp; + long inuse; + int action; /* what action READ/WRITE this socket waits for */ + curl_socket_t socket; /* mainly to ease debugging */ + void *socketp; /* settable by users with curl_multi_assign() */ +}; +/* bits for 'action' having no bits means this socket is not expecting any + action */ +#define SH_READ 1 +#define SH_WRITE 2 + +/* make sure this socket is present in the hash for this handle */ +static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, + curl_socket_t s, + struct SessionHandle *data) +{ + struct Curl_sh_entry *there = + Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + struct Curl_sh_entry *check; + + if(there) + /* it is present, return fine */ + return there; + + /* not present, add it */ + check = calloc(sizeof(struct Curl_sh_entry), 1); + if(!check) + return NULL; /* major failure */ + check->easy = data; + check->socket = s; + + /* make/add new hash entry */ + if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { + free(check); + return NULL; /* major failure */ + } + + return check; /* things are good in sockhash land */ +} + + +/* delete the given socket + handle from the hash */ +static void sh_delentry(struct curl_hash *sh, curl_socket_t s) +{ + struct Curl_sh_entry *there = + Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + + if(there) { + /* this socket is in the hash */ + /* We remove the hash entry. (This'll end up in a call to + sh_freeentry().) */ + Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); + } +} + +/* + * free a sockhash entry + */ +static void sh_freeentry(void *freethis) +{ + struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; + + free(p); +} + +/* + * sh_init() creates a new socket hash and returns the handle for it. + * + * Quote from README.multi_socket: + * + * "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. 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 struct curl_hash *sh_init(void) +{ + return Curl_hash_alloc(97, sh_freeentry); +} + +CURLM *curl_multi_init(void) +{ + struct Curl_multi *multi = (void *)calloc(sizeof(struct Curl_multi), 1); + + if(!multi) + return NULL; + + multi->type = CURL_MULTI_HANDLE; + + multi->hostcache = Curl_mk_dnscache(); + if(!multi->hostcache) { + /* failure, free mem and bail out */ + free(multi); + return NULL; + } + + multi->sockhash = sh_init(); + if(!multi->sockhash) { + /* failure, free mem and bail out */ + Curl_hash_destroy(multi->hostcache); + free(multi); + return NULL; + } + + multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1); + if(!multi->connc) { + Curl_hash_destroy(multi->hostcache); + free(multi); + return NULL; + } + + return (CURLM *) multi; +} + +CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *easy_handle) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct Curl_one_easy *easy; + struct closure *cl; + struct closure *prev=NULL; + + /* 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(easy_handle)) + return CURLM_BAD_EASY_HANDLE; + + /* Prevent users to add the same handle more than once! */ + if(((struct SessionHandle *)easy_handle)->multi) + /* possibly we should create a new unique error code for this condition */ + return CURLM_BAD_EASY_HANDLE; + + /* Now, time to add an easy handle to the multi stack */ + easy = (struct Curl_one_easy *)calloc(sizeof(struct Curl_one_easy), 1); + if(!easy) + return CURLM_OUT_OF_MEMORY; + + cl = multi->closure; + while(cl) { + struct closure *next = cl->next; + if(cl->easy_handle == (struct SessionHandle *)easy_handle) { + /* remove this handle from the closure list */ + free(cl); + if(prev) + prev->next = next; + else + multi->closure = next; + break; /* no need to continue since this handle can only be present once + in the list */ + } + cl = next; + } + + /* set the easy handle */ + easy->easy_handle = easy_handle; + multistate(easy, CURLM_STATE_INIT); + + /* for multi interface connections, we share DNS cache automatically if the + easy handle's one is currently private. */ + if (easy->easy_handle->dns.hostcache && + (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) { + Curl_hash_destroy(easy->easy_handle->dns.hostcache); + easy->easy_handle->dns.hostcache = NULL; + easy->easy_handle->dns.hostcachetype = HCACHE_NONE; + } + + if (!easy->easy_handle->dns.hostcache || + (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) { + easy->easy_handle->dns.hostcache = multi->hostcache; + easy->easy_handle->dns.hostcachetype = HCACHE_MULTI; + } + + if(easy->easy_handle->state.connc) { + if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) { + /* kill old private version */ + Curl_rm_connc(easy->easy_handle->state.connc); + /* point out our shared one instead */ + easy->easy_handle->state.connc = multi->connc; + } + /* else it is already using multi? */ + } + else + /* point out our shared one */ + easy->easy_handle->state.connc = multi->connc; + + /* Make sure the type is setup correctly */ + easy->easy_handle->state.connc->type = CONNCACHE_MULTI; + + /* We add this new entry first in the list. We make our 'next' point to the + previous next and our 'prev' point back to the 'first' struct */ + easy->next = multi->easy.next; + easy->prev = &multi->easy; + + /* make 'easy' the first node in the chain */ + multi->easy.next = easy; + + /* if there was a next node, make sure its 'prev' pointer links back to + the new node */ + if(easy->next) + easy->next->prev = easy; + + Curl_easy_addmulti(easy_handle, multi_handle); + + /* make the SessionHandle struct refer back to this struct */ + easy->easy_handle->set.one_easy = easy; + + /* increase the node-counter */ + multi->num_easy++; + + if((multi->num_easy * 4) > multi->connc->num) { + /* We want the connection cache to have plenty room. Before we supported + the shared cache every single easy handle had 5 entries in their cache + by default. */ + CURLcode res = Curl_ch_connc(easy_handle, multi->connc, + multi->connc->num*4); + if(res != CURLE_OK) + /* TODO: we need to do some cleaning up here! */ + return CURLM_OUT_OF_MEMORY; + } + + /* increase the alive-counter */ + multi->num_alive++; + + update_timer(multi); + return CURLM_OK; +} + +#if 0 +/* Debug-function, used like this: + * + * Curl_hash_print(multi->sockhash, debug_print_sock_hash); + * + * Enable the hash print function first by editing hash.c + */ +static void debug_print_sock_hash(void *p) +{ + struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; + + fprintf(stderr, " [easy %p/magic %x/socket %d]", + (void *)sh->easy, sh->easy->magic, sh->socket); +} +#endif + +CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct Curl_one_easy *easy; + + /* 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(curl_handle)) + return CURLM_BAD_EASY_HANDLE; + + /* scan through the list and remove the 'curl_handle' */ + easy = multi->easy.next; + while(easy) { + if(easy->easy_handle == (struct SessionHandle *)curl_handle) + break; + easy=easy->next; + } + + if(easy) { + bool premature = (bool)(easy->state != CURLM_STATE_COMPLETED); + + /* If the 'state' is not INIT or COMPLETED, we might need to do something + nice to put the easy_handle in a good known state when this returns. */ + if(premature) + /* this handle is "alive" so we need to count down the total number of + alive connections when this is removed */ + multi->num_alive--; + + if (easy->easy_handle->state.is_in_pipeline && + easy->state > CURLM_STATE_DO) { + /* If the handle is in a pipeline and has finished sending off its + request, we need to remember the fact that we want to remove this + handle but do the actual removal at a later time */ + easy->easy_handle->state.cancelled = TRUE; + return CURLM_OK; + } + + /* The timer must be shut down before easy->multi is set to NULL, + else the timenode will remain in the splay tree after + curl_easy_cleanup is called. */ + Curl_expire(easy->easy_handle, 0); + + if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { + /* clear out the usage of the shared DNS cache */ + easy->easy_handle->dns.hostcache = NULL; + easy->easy_handle->dns.hostcachetype = HCACHE_NONE; + } + + /* if we have a connection we must call Curl_done() here so that we + don't leave a half-baked one around */ + if(easy->easy_conn) { + /* Set up the association right */ + easy->easy_conn->data = easy->easy_handle; + + /* Curl_done() clears the conn->data field to lose the association + between the easy handle and the connection */ + Curl_done(&easy->easy_conn, easy->result, premature); + + if(easy->easy_conn) + /* the connection is still alive, set back the association to enable + the check below to trigger TRUE */ + easy->easy_conn->data = easy->easy_handle; + } + + /* If this easy_handle was the last one in charge for one or more + connections a the shared connection cache, we might need to keep this + handle around until either A) the connection is closed and killed + properly, or B) another easy_handle uses the connection. + + The reason why we need to have a easy_handle associated with a live + connection is simply that some connections will need a handle to get + closed down properly. Currently, the only connections that need to keep + a easy_handle handle around are using FTP(S). Such connections have + the PROT_CLOSEACTION bit set. + + Thus, we need to check for all connections in the shared cache that + points to this handle and are using PROT_CLOSEACTION. If there's any, + we need to add this handle to the list of "easy handles kept around for + nice connection closures". + */ + if(multi_conn_using(multi, easy->easy_handle)) { + /* There's at least one connection using this handle so we must keep + this handle around. We also keep the connection cache pointer + pointing to the shared one since that will be used on close as + well. */ + easy->easy_handle->state.shared_conn = multi; + + /* this handle is still being used by a shared connection cache and + thus we leave it around for now */ + add_closure(multi, easy->easy_handle); + } + + if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) { + /* if this was using the shared connection cache we clear the pointer + to that since we're not part of that handle anymore */ + easy->easy_handle->state.connc = NULL; + + /* and modify the connectindex since this handle can't point to the + connection cache anymore */ + if(easy->easy_conn) + easy->easy_conn->connectindex = -1; + } + + /* change state without using multistate(), only to make singlesocket() do + what we want */ + easy->state = CURLM_STATE_COMPLETED; + singlesocket(multi, easy); /* to let the application know what sockets + that vanish with this handle */ + + Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association + to this multi handle */ + + /* make the previous node point to our next */ + if(easy->prev) + easy->prev->next = easy->next; + /* make our next point to our previous node */ + if(easy->next) + easy->next->prev = easy->prev; + + easy->easy_handle->set.one_easy = NULL; /* detached */ + + /* NOTE NOTE NOTE + We do not touch the easy handle here! */ + if (easy->msg) + free(easy->msg); + free(easy); + + multi->num_easy--; /* one less to care about now */ + + update_timer(multi); + return CURLM_OK; + } + else + return CURLM_BAD_EASY_HANDLE; /* twasn't found */ +} + +bool Curl_multi_canPipeline(struct Curl_multi* multi) +{ + return multi->pipelining_enabled; +} + +static int waitconnect_getsock(struct connectdata *conn, + curl_socket_t *sock, + int numsocks) +{ + if(!numsocks) + return GETSOCK_BLANK; + + sock[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_WRITESOCK(0); +} + +static int domore_getsock(struct connectdata *conn, + curl_socket_t *sock, + int numsocks) +{ + if(!numsocks) + return GETSOCK_BLANK; + + /* When in DO_MORE state, we could be either waiting for us + to connect to a remote site, or we could wait for that site + to connect to us. It makes a difference in the way: if we + connect to the site we wait for the socket to become writable, if + the site connects to us we wait for it to become readable */ + sock[0] = conn->sock[SECONDARYSOCKET]; + + return GETSOCK_WRITESOCK(0); +} + +/* returns bitmapped flags for this handle and its sockets */ +static int multi_getsock(struct Curl_one_easy *easy, + curl_socket_t *socks, /* points to numsocks number + of sockets */ + int numsocks) +{ + if (easy->easy_handle->state.pipe_broke) { + return 0; + } + + if (easy->state > CURLM_STATE_CONNECT && + easy->state < CURLM_STATE_COMPLETED) { + /* Set up ownership correctly */ + easy->easy_conn->data = easy->easy_handle; + } + + switch(easy->state) { + case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */ + default: + /* this will get called with CURLM_STATE_COMPLETED when a handle is + removed */ + return 0; + + case CURLM_STATE_WAITRESOLVE: + return Curl_resolv_getsock(easy->easy_conn, socks, numsocks); + + case CURLM_STATE_PROTOCONNECT: + return Curl_protocol_getsock(easy->easy_conn, socks, numsocks); + + case CURLM_STATE_DOING: + return Curl_doing_getsock(easy->easy_conn, socks, numsocks); + + case CURLM_STATE_WAITCONNECT: + return waitconnect_getsock(easy->easy_conn, socks, numsocks); + + case CURLM_STATE_DO_MORE: + return domore_getsock(easy->easy_conn, socks, numsocks); + + case CURLM_STATE_PERFORM: + case CURLM_STATE_WAITPERFORM: + return Curl_single_getsock(easy->easy_conn, socks, numsocks); + } + +} + +CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, fd_set *write_fd_set, + fd_set *exc_fd_set, int *max_fd) +{ + /* 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_multi *multi=(struct Curl_multi *)multi_handle; + struct Curl_one_easy *easy; + int this_max_fd=-1; + curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; + int bitmap; + int i; + (void)exc_fd_set; /* not used */ + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + easy=multi->easy.next; + while(easy) { + bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); + + for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { + curl_socket_t s = CURL_SOCKET_BAD; + + if(bitmap & GETSOCK_READSOCK(i)) { + FD_SET(sockbunch[i], read_fd_set); + s = sockbunch[i]; + } + if(bitmap & GETSOCK_WRITESOCK(i)) { + FD_SET(sockbunch[i], write_fd_set); + s = sockbunch[i]; + } + if(s == CURL_SOCKET_BAD) + /* this socket is unused, break out of loop */ + break; + else { + if((int)s > this_max_fd) + this_max_fd = (int)s; + } + } + + easy = easy->next; /* check next handle */ + } + + *max_fd = this_max_fd; + + return CURLM_OK; +} + +static CURLMcode multi_runsingle(struct Curl_multi *multi, + struct Curl_one_easy *easy) +{ + struct Curl_message *msg = NULL; + bool connected; + bool async; + bool protocol_connect = 0; + bool dophase_done; + bool done; + CURLMcode result = CURLM_OK; + struct Curl_transfer_keeper *k; + + do { + + if(!GOOD_EASY_HANDLE(easy->easy_handle)) + return CURLM_BAD_EASY_HANDLE; + + if (easy->easy_handle->state.pipe_broke) { + infof(easy->easy_handle, "Pipe broke: handle 0x%x, url = %s\n", + easy, easy->easy_handle->reqdata.path); + if(easy->easy_handle->state.is_in_pipeline) { + /* Head back to the CONNECT state */ + multistate(easy, CURLM_STATE_CONNECT); + result = CURLM_CALL_MULTI_PERFORM; + easy->result = CURLE_OK; + } else { + easy->result = CURLE_COULDNT_CONNECT; + multistate(easy, CURLM_STATE_COMPLETED); + } + + easy->easy_handle->state.pipe_broke = FALSE; + easy->easy_conn = NULL; + break; + } + + if (easy->state > CURLM_STATE_CONNECT && + easy->state < CURLM_STATE_COMPLETED) { + /* Make sure we set the connection's current owner */ + easy->easy_conn->data = easy->easy_handle; + } + + if (CURLM_STATE_WAITCONNECT <= easy->state && + easy->state <= CURLM_STATE_DO && + easy->easy_handle->change.url_changed) { + char *gotourl; + Curl_posttransfer(easy->easy_handle); + + easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); + /* We make sure that the pipe broken flag is reset + because in this case, it isn't an actual break */ + easy->easy_handle->state.pipe_broke = FALSE; + if(CURLE_OK == easy->result) { + gotourl = strdup(easy->easy_handle->change.url); + if(gotourl) { + easy->easy_handle->change.url_changed = FALSE; + easy->result = Curl_follow(easy->easy_handle, gotourl, FALSE); + if(CURLE_OK == easy->result) + multistate(easy, CURLM_STATE_CONNECT); + else + free(gotourl); + } + else { + easy->result = CURLE_OUT_OF_MEMORY; + multistate(easy, CURLM_STATE_COMPLETED); + break; + } + } + } + + easy->easy_handle->change.url_changed = FALSE; + + switch(easy->state) { + case CURLM_STATE_INIT: + /* init this transfer. */ + easy->result=Curl_pretransfer(easy->easy_handle); + + if(CURLE_OK == easy->result) { + /* after init, go CONNECT */ + multistate(easy, CURLM_STATE_CONNECT); + result = CURLM_CALL_MULTI_PERFORM; + + easy->easy_handle->state.used_interface = Curl_if_multi; + } + break; + + case CURLM_STATE_CONNECT: + /* Connect. We get a connection identifier filled in. */ + Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE); + easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn, + &async, &protocol_connect); + + if(CURLE_OK == easy->result) { + /* Add this handle to the send pipeline */ + Curl_addHandleToPipeline(easy->easy_handle, + easy->easy_conn->send_pipe); + + if(async) + /* We're now waiting for an asynchronous name lookup */ + multistate(easy, CURLM_STATE_WAITRESOLVE); + else { + /* after the connect has been sent off, go WAITCONNECT unless the + protocol connect is already done and we can go directly to + WAITDO! */ + result = CURLM_CALL_MULTI_PERFORM; + + if(protocol_connect) { + multistate(easy, CURLM_STATE_WAITDO); + } else { + multistate(easy, CURLM_STATE_WAITCONNECT); + } + } + } + break; + + case CURLM_STATE_WAITRESOLVE: + /* awaiting an asynch name resolve to complete */ + { + struct Curl_dns_entry *dns = NULL; + + /* check if we have the name resolved by now */ + easy->result = Curl_is_resolved(easy->easy_conn, &dns); + + if(dns) { + /* Perform the next step in the connection phase, and then move on + to the WAITCONNECT state */ + easy->result = Curl_async_resolved(easy->easy_conn, + &protocol_connect); + + if(CURLE_OK != easy->result) + /* if Curl_async_resolved() returns failure, the connection struct + is already freed and gone */ + easy->easy_conn = NULL; /* no more connection */ + else { + /* call again please so that we get the next socket setup */ + result = CURLM_CALL_MULTI_PERFORM; + if(protocol_connect) + multistate(easy, CURLM_STATE_DO); + else + multistate(easy, CURLM_STATE_WAITCONNECT); + } + } + + if(CURLE_OK != easy->result) { + /* failure detected */ + Curl_disconnect(easy->easy_conn); /* disconnect properly */ + easy->easy_conn = NULL; /* no more connection */ + break; + } + } + break; + + case CURLM_STATE_WAITCONNECT: + /* awaiting a completion of an asynch connect */ + easy->result = Curl_is_connected(easy->easy_conn, + FIRSTSOCKET, + &connected); + if(connected) + easy->result = Curl_protocol_connect(easy->easy_conn, + &protocol_connect); + + if(CURLE_OK != easy->result) { + /* failure detected */ + Curl_disconnect(easy->easy_conn); /* close the connection */ + easy->easy_conn = NULL; /* no more connection */ + break; + } + + if(connected) { + if(!protocol_connect) { + /* We have a TCP connection, but 'protocol_connect' may be false + and then we continue to 'STATE_PROTOCONNECT'. If protocol + connect is TRUE, we move on to STATE_DO. */ + multistate(easy, CURLM_STATE_PROTOCONNECT); + } + else { + /* after the connect has completed, go WAITDO */ + multistate(easy, CURLM_STATE_WAITDO); + + result = CURLM_CALL_MULTI_PERFORM; + } + } + break; + + case CURLM_STATE_PROTOCONNECT: + /* protocol-specific connect phase */ + easy->result = Curl_protocol_connecting(easy->easy_conn, + &protocol_connect); + if(protocol_connect) { + /* after the connect has completed, go WAITDO */ + multistate(easy, CURLM_STATE_WAITDO); + result = CURLM_CALL_MULTI_PERFORM; + } + else if(easy->result) { + /* failure detected */ + Curl_posttransfer(easy->easy_handle); + Curl_done(&easy->easy_conn, easy->result, FALSE); + Curl_disconnect(easy->easy_conn); /* close the connection */ + easy->easy_conn = NULL; /* no more connection */ + } + break; + + case CURLM_STATE_WAITDO: + /* Wait for our turn to DO when we're pipelining requests */ +#ifdef CURLDEBUG + infof(easy->easy_handle, "Conn %d send pipe %d inuse %d athead %d\n", + easy->easy_conn->connectindex, + easy->easy_conn->send_pipe->size, + easy->easy_conn->writechannel_inuse, + Curl_isHandleAtHead(easy->easy_handle, + easy->easy_conn->send_pipe)); +#endif + if (!easy->easy_conn->writechannel_inuse && + Curl_isHandleAtHead(easy->easy_handle, + easy->easy_conn->send_pipe)) { + /* Grab the channel */ + easy->easy_conn->writechannel_inuse = TRUE; + multistate(easy, CURLM_STATE_DO); + result = CURLM_CALL_MULTI_PERFORM; + } + break; + + case CURLM_STATE_DO: + if(easy->easy_handle->set.connect_only) { + /* keep connection open for application to use the socket */ + easy->easy_conn->bits.close = FALSE; + multistate(easy, CURLM_STATE_DONE); + easy->result = CURLE_OK; + result = CURLM_OK; + } + else { + /* Perform the protocol's DO action */ + easy->result = Curl_do(&easy->easy_conn, + &dophase_done); + + if(CURLE_OK == easy->result) { + + if(!dophase_done) { + /* DO was not completed in one function call, we must continue + DOING... */ + multistate(easy, CURLM_STATE_DOING); + result = CURLM_OK; + } + + /* after DO, go DO_DONE... or DO_MORE */ + else if(easy->easy_conn->bits.do_more) { + /* we're supposed to do more, but we need to sit down, relax + and wait a little while first */ + multistate(easy, CURLM_STATE_DO_MORE); + result = CURLM_OK; + } + else { + /* we're done with the DO, now DO_DONE */ + easy->result = Curl_readwrite_init(easy->easy_conn); + if(CURLE_OK == easy->result) { + multistate(easy, CURLM_STATE_DO_DONE); + result = CURLM_CALL_MULTI_PERFORM; + } + } + } + else { + /* failure detected */ + Curl_posttransfer(easy->easy_handle); + Curl_done(&easy->easy_conn, easy->result, FALSE); + Curl_disconnect(easy->easy_conn); /* close the connection */ + easy->easy_conn = NULL; /* no more connection */ + } + } + break; + + case CURLM_STATE_DOING: + /* we continue DOING until the DO phase is complete */ + easy->result = Curl_protocol_doing(easy->easy_conn, + &dophase_done); + if(CURLE_OK == easy->result) { + if(dophase_done) { + /* after DO, go PERFORM... or DO_MORE */ + if(easy->easy_conn->bits.do_more) { + /* we're supposed to do more, but we need to sit down, relax + and wait a little while first */ + multistate(easy, CURLM_STATE_DO_MORE); + result = CURLM_OK; + } + else { + /* we're done with the DO, now DO_DONE */ + easy->result = Curl_readwrite_init(easy->easy_conn); + if(CURLE_OK == easy->result) { + multistate(easy, CURLM_STATE_DO_DONE); + result = CURLM_CALL_MULTI_PERFORM; + } + } + } /* dophase_done */ + } + else { + /* failure detected */ + Curl_posttransfer(easy->easy_handle); + Curl_done(&easy->easy_conn, easy->result, FALSE); + Curl_disconnect(easy->easy_conn); /* close the connection */ + easy->easy_conn = NULL; /* no more connection */ + } + break; + + case CURLM_STATE_DO_MORE: + /* Ready to do more? */ + easy->result = Curl_is_connected(easy->easy_conn, + SECONDARYSOCKET, + &connected); + if(connected) { + /* + * When we are connected, DO MORE and then go DO_DONE + */ + easy->result = Curl_do_more(easy->easy_conn); + + if(CURLE_OK == easy->result) + easy->result = Curl_readwrite_init(easy->easy_conn); + else + /* Remove ourselves from the send pipeline */ + Curl_removeHandleFromPipeline(easy->easy_handle, + easy->easy_conn->send_pipe); + + if(CURLE_OK == easy->result) { + multistate(easy, CURLM_STATE_DO_DONE); + result = CURLM_CALL_MULTI_PERFORM; + } + } + break; + + case CURLM_STATE_DO_DONE: + /* Remove ourselves from the send pipeline */ + Curl_removeHandleFromPipeline(easy->easy_handle, + easy->easy_conn->send_pipe); + /* Add ourselves to the recv pipeline */ + Curl_addHandleToPipeline(easy->easy_handle, + easy->easy_conn->recv_pipe); + multistate(easy, CURLM_STATE_WAITPERFORM); + result = CURLM_CALL_MULTI_PERFORM; + break; + + case CURLM_STATE_WAITPERFORM: +#ifdef CURLDEBUG + infof(easy->easy_handle, "Conn %d recv pipe %d inuse %d athead %d\n", + easy->easy_conn->connectindex, + easy->easy_conn->recv_pipe->size, + easy->easy_conn->readchannel_inuse, + Curl_isHandleAtHead(easy->easy_handle, + easy->easy_conn->recv_pipe)); +#endif + /* Wait for our turn to PERFORM */ + if (!easy->easy_conn->readchannel_inuse && + Curl_isHandleAtHead(easy->easy_handle, + easy->easy_conn->recv_pipe)) { + /* Grab the channel */ + easy->easy_conn->readchannel_inuse = TRUE; + multistate(easy, CURLM_STATE_PERFORM); + result = CURLM_CALL_MULTI_PERFORM; + } + break; + + case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ + /* if both rates are within spec, resume transfer */ + Curl_pgrsUpdate(easy->easy_conn); + if ( ( ( easy->easy_handle->set.max_send_speed == 0 ) || + ( easy->easy_handle->progress.ulspeed < + easy->easy_handle->set.max_send_speed ) ) && + ( ( easy->easy_handle->set.max_recv_speed == 0 ) || + ( easy->easy_handle->progress.dlspeed < + easy->easy_handle->set.max_recv_speed ) ) + ) + multistate(easy, CURLM_STATE_PERFORM); + break; + + case CURLM_STATE_PERFORM: + /* check if over speed */ + if ( ( ( easy->easy_handle->set.max_send_speed > 0 ) && + ( easy->easy_handle->progress.ulspeed > + easy->easy_handle->set.max_send_speed ) ) || + ( ( easy->easy_handle->set.max_recv_speed > 0 ) && + ( easy->easy_handle->progress.dlspeed > + easy->easy_handle->set.max_recv_speed ) ) + ) { + /* Transfer is over the speed limit. Change state. TODO: Call + * Curl_expire() with the time left until we're targeted to be below + * the speed limit again. */ + multistate(easy, CURLM_STATE_TOOFAST ); + break; + } + + /* read/write data if it is ready to do so */ + easy->result = Curl_readwrite(easy->easy_conn, &done); + + k = &easy->easy_handle->reqdata.keep; + + if (!(k->keepon & KEEP_READ)) { + /* We're done reading */ + easy->easy_conn->readchannel_inuse = FALSE; + } + + if (!(k->keepon & KEEP_WRITE)) { + /* We're done writing */ + easy->easy_conn->writechannel_inuse = FALSE; + } + + if(easy->result) { + /* The transfer phase returned error, we mark the connection to get + * closed to prevent being re-used. This is becasue we can't + * possibly know if the connection is in a good shape or not now. */ + easy->easy_conn->bits.close = TRUE; + + if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) { + /* if we failed anywhere, we must clean up the secondary socket if + it was used */ + sclose(easy->easy_conn->sock[SECONDARYSOCKET]); + easy->easy_conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + } + Curl_posttransfer(easy->easy_handle); + Curl_done(&easy->easy_conn, easy->result, FALSE); + } + else if(TRUE == done) { + char *newurl; + bool retry = Curl_retry_request(easy->easy_conn, &newurl); + + /* call this even if the readwrite function returned error */ + Curl_posttransfer(easy->easy_handle); + + /* When we follow redirects, must to go back to the CONNECT state */ + if(easy->easy_handle->reqdata.newurl || retry) { + Curl_removeHandleFromPipeline(easy->easy_handle, + easy->easy_conn->recv_pipe); + if(!retry) { + /* if the URL is a follow-location and not just a retried request + then figure out the URL here */ + newurl = easy->easy_handle->reqdata.newurl; + easy->easy_handle->reqdata.newurl = NULL; + } + easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); + if(easy->result == CURLE_OK) + easy->result = Curl_follow(easy->easy_handle, newurl, retry); + if(CURLE_OK == easy->result) { + multistate(easy, CURLM_STATE_CONNECT); + result = CURLM_CALL_MULTI_PERFORM; + } + else + /* Since we "took it", we are in charge of freeing this on + failure */ + free(newurl); + } + else { + /* after the transfer is done, go DONE */ + multistate(easy, CURLM_STATE_DONE); + result = CURLM_CALL_MULTI_PERFORM; + } + } + + break; + + case CURLM_STATE_DONE: + /* Remove ourselves from the receive pipeline */ + Curl_removeHandleFromPipeline(easy->easy_handle, + easy->easy_conn->recv_pipe); + easy->easy_handle->state.is_in_pipeline = FALSE; + + if (easy->easy_conn->bits.stream_was_rewound) { + /* This request read past its response boundary so we quickly + let the other requests consume those bytes since there is no + guarantee that the socket will become active again */ + result = CURLM_CALL_MULTI_PERFORM; + } + + if (!easy->easy_handle->state.cancelled) { + /* post-transfer command */ + easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); + + /* after we have DONE what we're supposed to do, go COMPLETED, and + it doesn't matter what the Curl_done() returned! */ + multistate(easy, CURLM_STATE_COMPLETED); + } + + break; + + case CURLM_STATE_COMPLETED: + if (easy->easy_handle->state.cancelled) + /* Go into the CANCELLED state if we were cancelled */ + multistate(easy, CURLM_STATE_CANCELLED); + + /* this is a completed transfer, it is likely to still be connected */ + + /* This node should be delinked from the list now and we should post + an information message that we are complete. */ + break; + + case CURLM_STATE_CANCELLED: + /* Cancelled transfer, wait to be cleaned up */ + break; + + default: + return CURLM_INTERNAL_ERROR; + } + + if(CURLM_STATE_COMPLETED != easy->state) { + if(CURLE_OK != easy->result) { + /* + * If an error was returned, and we aren't in completed state now, + * then we go to completed and consider this transfer aborted. + */ + easy->easy_handle->state.is_in_pipeline = FALSE; + easy->easy_handle->state.pipe_broke = FALSE; + + if(easy->easy_conn) { + /* if this has a connection, unsubscribe from the pipelines */ + easy->easy_conn->writechannel_inuse = FALSE; + easy->easy_conn->readchannel_inuse = FALSE; + } + multistate(easy, CURLM_STATE_COMPLETED); + } + } + + } while (easy->easy_handle->change.url_changed); + + if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) { + if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { + /* clear out the usage of the shared DNS cache */ + easy->easy_handle->dns.hostcache = NULL; + easy->easy_handle->dns.hostcachetype = HCACHE_NONE; + } + + /* now add a node to the Curl_message linked list with this info */ + msg = (struct Curl_message *)malloc(sizeof(struct Curl_message)); + + if(!msg) + return CURLM_OUT_OF_MEMORY; + + msg->extmsg.msg = CURLMSG_DONE; + msg->extmsg.easy_handle = easy->easy_handle; + msg->extmsg.data.result = easy->result; + msg->next = NULL; + + easy->msg = msg; + easy->msg_num = 1; /* there is one unread message here */ + + multi->num_msgs++; /* increase message counter */ + } + + return result; +} + + +CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct Curl_one_easy *easy; + CURLMcode returncode=CURLM_OK; + struct Curl_tree *t; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + easy=multi->easy.next; + while(easy) { + CURLMcode result; + + if (easy->easy_handle->state.cancelled && + easy->state == CURLM_STATE_CANCELLED) { + /* Remove cancelled handles once it's safe to do so */ + Curl_multi_rmeasy(multi_handle, easy->easy_handle); + easy->easy_handle = NULL; + easy = easy->next; + continue; + } + + result = multi_runsingle(multi, easy); + if(result) + returncode = result; + + easy = easy->next; /* operate on next handle */ + } + + /* + * Simply remove all expired timers from the splay since handles are dealt + * with unconditionally by this function and curl_multi_timeout() requires + * that already passed/handled expire times are removed from the splay. + */ + do { + struct timeval now = Curl_tvnow(); + int key = now.tv_sec; /* drop the usec part */ + + multi->timetree = Curl_splaygetbest(key, multi->timetree, &t); + if (t) { + struct SessionHandle *d = t->payload; + struct timeval* tv = &d->state.expiretime; + + /* clear the expire times within the handles that we remove from the + splay tree */ + tv->tv_sec = 0; + tv->tv_usec = 0; + } + + } while(t); + + *running_handles = multi->num_alive; + + if ( CURLM_OK == returncode ) + update_timer(multi); + return returncode; +} + +/* This is called when an easy handle is cleanup'ed that is part of a multi + handle */ +void Curl_multi_rmeasy(void *multi_handle, CURL *easy_handle) +{ + curl_multi_remove_handle(multi_handle, easy_handle); +} + + +CURLMcode curl_multi_cleanup(CURLM *multi_handle) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct Curl_one_easy *easy; + struct Curl_one_easy *nexteasy; + int i; + struct closure *cl; + struct closure *n; + + if(GOOD_MULTI_HANDLE(multi)) { + multi->type = 0; /* not good anymore */ + Curl_hash_destroy(multi->hostcache); + Curl_hash_destroy(multi->sockhash); + + /* go over all connections that have close actions */ + for(i=0; i< multi->connc->num; i++) { + if(multi->connc->connects[i] && + multi->connc->connects[i]->protocol & PROT_CLOSEACTION) { + Curl_disconnect(multi->connc->connects[i]); + multi->connc->connects[i] = NULL; + } + } + /* now walk through the list of handles we kept around only to be + able to close connections "properly" */ + cl = multi->closure; + while(cl) { + cl->easy_handle->state.shared_conn = NULL; /* no more shared */ + if(cl->easy_handle->state.closed) + /* close handle only if curl_easy_cleanup() already has been called + for this easy handle */ + Curl_close(cl->easy_handle); + n = cl->next; + free(cl); + cl= n; + } + + Curl_rm_connc(multi->connc); + + /* remove all easy handles */ + easy = multi->easy.next; + while(easy) { + nexteasy=easy->next; + if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { + /* clear out the usage of the shared DNS cache */ + easy->easy_handle->dns.hostcache = NULL; + easy->easy_handle->dns.hostcachetype = HCACHE_NONE; + } + + /* Clear the pointer to the connection cache */ + easy->easy_handle->state.connc = NULL; + + Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */ + + if (easy->msg) + free(easy->msg); + free(easy); + easy = nexteasy; + } + + free(multi); + + return CURLM_OK; + } + else + return CURLM_BAD_HANDLE; +} + +CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + + *msgs_in_queue = 0; /* default to none */ + + if(GOOD_MULTI_HANDLE(multi)) { + struct Curl_one_easy *easy; + + if(!multi->num_msgs) + return NULL; /* no messages left to return */ + + easy=multi->easy.next; + while(easy) { + if(easy->msg_num) { + easy->msg_num--; + break; + } + easy = easy->next; + } + if(!easy) + return NULL; /* this means internal count confusion really */ + + multi->num_msgs--; + *msgs_in_queue = multi->num_msgs; + + return &easy->msg->extmsg; + } + else + return NULL; +} + +/* + * singlesocket() checks what sockets we deal with and their "action state" + * and if we have a different state in any of those sockets from last time we + * call the callback accordingly. + */ +static void singlesocket(struct Curl_multi *multi, + struct Curl_one_easy *easy) +{ + curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; + int i; + struct Curl_sh_entry *entry; + curl_socket_t s; + int num; + unsigned int curraction; + + memset(&socks, 0, sizeof(socks)); + for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) + socks[i] = CURL_SOCKET_BAD; + + /* Fill in the 'current' struct with the state as it is now: what sockets to + supervise and for what actions */ + curraction = multi_getsock(easy, socks, MAX_SOCKSPEREASYHANDLE); + + /* 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< MAX_SOCKSPEREASYHANDLE) && + (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))); + i++) { + int action = CURL_POLL_NONE; + + s = socks[i]; + + /* get it from the hash */ + entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + + if(curraction & GETSOCK_READSOCK(i)) + action |= CURL_POLL_IN; + if(curraction & GETSOCK_WRITESOCK(i)) + action |= CURL_POLL_OUT; + + if(entry) { + /* yeps, already present so check if it has the same action set */ + if(entry->action == action) + /* same, continue */ + continue; + } + else { + /* this is a socket we didn't have before, add it! */ + entry = sh_addentry(multi->sockhash, s, easy->easy_handle); + if(!entry) + /* fatal */ + return; + } + + multi->socket_cb(easy->easy_handle, + s, + action, + multi->socket_userp, + entry ? entry->socketp : NULL); + + entry->action = action; /* store the current action state */ + } + + num = i; /* number of sockets */ + + /* when we've walked over all the sockets we should have right now, we must + make sure to detect sockets that are removed */ + for(i=0; i< easy->numsocks; i++) { + int j; + s = easy->sockets[i]; + for(j=0; jsockhash, (char *)&s, sizeof(s)); + if(entry) { + /* just a precaution, this socket really SHOULD be in the hash already + but in case it isn't, we don't have to tell the app to remove it + either since it never got to know about it */ + multi->socket_cb(easy->easy_handle, + s, + CURL_POLL_REMOVE, + multi->socket_userp, + entry ? entry->socketp : NULL); + + sh_delentry(multi->sockhash, s); + } + } + } + + memcpy(easy->sockets, socks, num*sizeof(curl_socket_t)); + easy->numsocks = num; +} + +static CURLMcode multi_socket(struct Curl_multi *multi, + bool checkall, + curl_socket_t s, + int *running_handles) +{ + CURLMcode result = CURLM_OK; + struct SessionHandle *data = NULL; + struct Curl_tree *t; + + if(checkall) { + struct Curl_one_easy *easyp; + /* *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 */ + easyp=multi->easy.next; + while(easyp) { + singlesocket(multi, easyp); + easyp = easyp->next; + } + + /* or should we fall-through and do the timer-based stuff? */ + return result; + } + else if (s != CURL_SOCKET_TIMEOUT) { + + struct Curl_sh_entry *entry = + Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + + if(!entry) + /* unmatched socket, major problemo! */ + return CURLM_BAD_SOCKET; /* better return code? */ + + data = entry->easy; + + if(data->magic != CURLEASY_MAGIC_NUMBER) + /* bad bad bad bad bad bad bad */ + return CURLM_INTERNAL_ERROR; + + result = multi_runsingle(multi, data->set.one_easy); + + if(result == CURLM_OK) + /* get the socket(s) and check if the state has been changed since + last */ + singlesocket(multi, data->set.one_easy); + + /* 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 */ + } + + /* + * 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 { + int key; + struct timeval now; + + /* the first loop lap 'data' can be NULL */ + if(data) { + result = multi_runsingle(multi, data->set.one_easy); + + if(result == CURLM_OK) + /* get the socket(s) and check if the state has been changed since + last */ + singlesocket(multi, data->set.one_easy); + } + + /* Check if there's one (more) expired timer to deal with! This function + extracts a matching node if there is one */ + + now = Curl_tvnow(); + key = now.tv_sec; /* drop the usec part */ + + multi->timetree = Curl_splaygetbest(key, multi->timetree, &t); + if(t) { + /* assign 'data' to be the easy handle we just removed from the splay + tree */ + data = t->payload; + /* clear the expire time within the handle we removed from the + splay tree */ + data->state.expiretime.tv_sec = 0; + data->state.expiretime.tv_usec = 0; + } + + } while(t); + + *running_handles = multi->num_alive; + return result; +} + +CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + CURLMcode res = CURLM_OK; + va_list param; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + va_start(param, option); + + switch(option) { + case CURLMOPT_SOCKETFUNCTION: + multi->socket_cb = va_arg(param, curl_socket_callback); + break; + case CURLMOPT_SOCKETDATA: + multi->socket_userp = va_arg(param, void *); + break; + case CURLMOPT_PIPELINING: + multi->pipelining_enabled = (bool)(0 != va_arg(param, long)); + break; + case CURLMOPT_TIMERFUNCTION: + multi->timer_cb = va_arg(param, curl_multi_timer_callback); + break; + case CURLMOPT_TIMERDATA: + multi->timer_userp = va_arg(param, void *); + break; + default: + res = CURLM_UNKNOWN_OPTION; + break; + } + va_end(param); + return res; +} + + +CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles) +{ + CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, + running_handles); + if (CURLM_OK == result) + update_timer((struct Curl_multi *)multi_handle); + return result; +} + +CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) + +{ + CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, + TRUE, CURL_SOCKET_BAD, running_handles); + if (CURLM_OK == result) + update_timer((struct Curl_multi *)multi_handle); + return result; +} + +static CURLMcode multi_timeout(struct Curl_multi *multi, + long *timeout_ms) +{ + if(multi->timetree) { + /* we have a tree of expire times */ + struct timeval now = Curl_tvnow(); + + /* splay the lowest to the bottom */ + multi->timetree = Curl_splay(0, multi->timetree); + + /* At least currently, the splay key is a time_t for the expire time */ + *timeout_ms = (multi->timetree->key - now.tv_sec) * 1000 - + now.tv_usec/1000; + if(*timeout_ms < 0) + /* 0 means immediately */ + *timeout_ms = 0; + } + else + *timeout_ms = -1; + + return CURLM_OK; +} + +CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *timeout_ms) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + + /* First, make some basic checks that the CURLM handle is a good handle */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + return multi_timeout(multi, timeout_ms); +} + +/* + * Tell the application it should update its timers, if it subscribes to the + * update timer callback. + */ +static int update_timer(struct Curl_multi *multi) +{ + long timeout_ms; + if (!multi->timer_cb) + return 0; + if ( multi_timeout(multi, &timeout_ms) != CURLM_OK ) + return -1; + if ( timeout_ms < 0 ) + return 0; + + /* 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(multi->timetree->key == multi->timer_lastcall) + return 0; + + multi->timer_lastcall = multi->timetree->key; + + return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); +} + +/* given a number of milliseconds from now to use to set the 'act before + this'-time for the transfer, to be extracted by curl_multi_timeout() */ +void Curl_expire(struct SessionHandle *data, long milli) +{ + struct Curl_multi *multi = data->multi; + struct timeval *nowp = &data->state.expiretime; + int rc; + + /* this is only interesting for multi-interface using libcurl, and only + while there is still a multi interface struct remaining! */ + if(!multi) + return; + + if(!milli) { + /* No timeout, clear the time data. */ + if(nowp->tv_sec) { + /* Since this is an cleared time, we must remove the previous entry from + the splay tree */ + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error clearing splay node = %d\n", rc); + infof(data, "Expire cleared\n"); + nowp->tv_sec = 0; + nowp->tv_usec = 0; + } + } + else { + struct timeval set; + int rest; + + set = Curl_tvnow(); + set.tv_sec += milli/1000; + set.tv_usec += (milli%1000)*1000; + + rest = (int)(set.tv_usec - 1000000); + if(rest > 0) { + /* bigger than a full microsec */ + set.tv_sec++; + set.tv_usec -= 1000000; + } + + if(nowp->tv_sec) { + /* 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. */ + long diff = curlx_tvdiff(set, *nowp); + if(diff > 0) + /* the new expire time was later so we don't change this */ + return; + + /* Since this is an updated time, we must remove the previous entry from + the splay tree first and then re-add the new value */ + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error removing splay node = %d\n", rc); + } + + *nowp = set; +#if 0 + infof(data, "Expire at %ld / %ld (%ldms)\n", + (long)nowp->tv_sec, (long)nowp->tv_usec, milli); +#endif + data->state.timenode.payload = data; + multi->timetree = Curl_splayinsert((int)nowp->tv_sec, + multi->timetree, + &data->state.timenode); + } +#if 0 + Curl_splayprint(multi->timetree, 0, TRUE); +#endif +} + +CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t s, void *hashp) +{ + struct Curl_sh_entry *there = NULL; + struct Curl_multi *multi = (struct Curl_multi *)multi_handle; + + if(s != CURL_SOCKET_BAD) + there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t)); + + if(!there) + return CURLM_BAD_SOCKET; + + there->socketp = hashp; + + return CURLM_OK; +} + +static bool multi_conn_using(struct Curl_multi *multi, + struct SessionHandle *data) +{ + /* any live CLOSEACTION-connections pointing to the give 'data' ? */ + int i; + + for(i=0; i< multi->connc->num; i++) { + if(multi->connc->connects[i] && + (multi->connc->connects[i]->data == data) && + multi->connc->connects[i]->protocol & PROT_CLOSEACTION) + return TRUE; + } + + return FALSE; +} + +/* Add the given data pointer to the list of 'closure handles' that are kept + around only to be able to close some connections nicely - just make sure + that this handle isn't already added, like for the cases when an easy + handle is removed, added and removed again... */ +static void add_closure(struct Curl_multi *multi, + struct SessionHandle *data) +{ + int i; + struct closure *cl = (struct closure *)calloc(sizeof(struct closure), 1); + struct closure *p=NULL; + struct closure *n; + if(cl) { + cl->easy_handle = data; + cl->next = multi->closure; + multi->closure = cl; + } + + p = multi->closure; + cl = p->next; /* start immediately on the second since the first is the one + we just added and it is _very_ likely to actually exist + used in the cache since that's the whole purpose of adding + it to this list! */ + + /* When adding, scan through all the other currently kept handles and see if + there are any connections still referring to them and kill them if not. */ + while(cl) { + bool inuse = FALSE; + for(i=0; i< multi->connc->num; i++) { + if(multi->connc->connects[i] && + (multi->connc->connects[i]->data == cl->easy_handle)) { + inuse = TRUE; + break; + } + } + + n = cl->next; + + if(!inuse) { + /* cl->easy_handle is now killable */ + infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle); + /* unmark it as not having a connection around that uses it anymore */ + cl->easy_handle->state.shared_conn= NULL; + Curl_close(cl->easy_handle); + if(p) + p->next = n; + else + multi->closure = n; + free(cl); + } + else + p = cl; + + cl = n; + } + +} + +#ifdef CURLDEBUG +void curl_multi_dump(CURLM *multi_handle) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct Curl_one_easy *easy; + int i; + fprintf(stderr, "* Multi status: %d handles, %d alive\n", + multi->num_easy, multi->num_alive); + for(easy=multi->easy.next; easy; easy = easy->next) { + if(easy->state != CURLM_STATE_COMPLETED) { + /* only display handles that are not completed */ + fprintf(stderr, "handle %p, state %s, %d sockets\n", + (void *)easy->easy_handle, + statename[easy->state], easy->numsocks); + for(i=0; i < easy->numsocks; i++) { + curl_socket_t s = easy->sockets[i]; + struct Curl_sh_entry *entry = + Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + + fprintf(stderr, "%d ", (int)s); + if(!entry) { + fprintf(stderr, "INTERNAL CONFUSION\n"); + continue; + } + fprintf(stderr, "[%s %s] ", + entry->action&CURL_POLL_IN?"RECVING":"", + entry->action&CURL_POLL_OUT?"SENDING":""); + } + if(easy->numsocks) + fprintf(stderr, "\n"); + } + } +} +#endif diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h new file mode 100644 index 0000000..800aa0f --- /dev/null +++ b/Utilities/cmcurl/lib/multiif.h @@ -0,0 +1,46 @@ +#ifndef __MULTIIF_H +#define __MULTIIF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * Prototypes for library-wide functions provided by multi.c + */ +void Curl_expire(struct SessionHandle *data, long milli); + +void Curl_multi_rmeasy(void *multi, CURL *data); + +bool Curl_multi_canPipeline(struct Curl_multi* multi); + +/* the write bits start at bit 16 for the *getsock() bitmap */ +#define GETSOCK_WRITEBITSTART 16 + +#define GETSOCK_BLANK 0 /* no bits set */ + +/* set the bit for the given sock number to make the bitmap for writable */ +#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x))) + +/* set the bit for the given sock number to make the bitmap for readable */ +#define GETSOCK_READSOCK(x) (1 << (x)) + +#endif /* __MULTIIF_H */ diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c new file mode 100644 index 0000000..54d1759 --- /dev/null +++ b/Utilities/cmcurl/lib/netrc.c @@ -0,0 +1,247 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef VMS +#include +#endif + +#include +#include "netrc.h" + +#include "strequal.h" +#include "strtok.h" +#include "memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +/* Debug this single source file with: + 'make netrc' then run './netrc'! + + Oh, make sure you have a .netrc file too ;-) + */ + +/* Get user and password from .netrc when given a machine name */ + +enum { + NOTHING, + HOSTFOUND, /* the 'machine' keyword was found */ + HOSTCOMPLETE, /* the machine name following the keyword was found too */ + HOSTVALID, /* this is "our" machine! */ + + HOSTEND /* LAST enum */ +}; + +/* make sure we have room for at least this size: */ +#define LOGINSIZE 64 +#define PASSWORDSIZE 64 + +/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ +int Curl_parsenetrc(char *host, + char *login, + char *password, + char *netrcfile) +{ + FILE *file; + int retcode=1; + int specific_login = (login[0] != 0); + char *home = NULL; + bool home_alloc = FALSE; + bool netrc_alloc = FALSE; + int state=NOTHING; + + char state_login=0; /* Found a login keyword */ + char state_password=0; /* Found a password keyword */ + int state_our_login=FALSE; /* With specific_login, found *our* login name */ + +#define NETRC DOT_CHAR "netrc" + +#ifdef CURLDEBUG + { + /* This is a hack to allow testing. + * If compiled with --enable-debug and CURL_DEBUG_NETRC is defined, + * then it's the path to a substitute .netrc for testing purposes *only* */ + + char *override = curl_getenv("CURL_DEBUG_NETRC"); + + if (override) { + fprintf(stderr, "NETRC: overridden " NETRC " file: %s\n", override); + netrcfile = override; + netrc_alloc = TRUE; + } + } +#endif /* CURLDEBUG */ + if(!netrcfile) { + home = curl_getenv("HOME"); /* portable environment reader */ + if(home) { + home_alloc = TRUE; +#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) + } + else { + struct passwd *pw; + pw= getpwuid(geteuid()); + if (pw) { +#ifdef VMS + home = decc$translate_vms(pw->pw_dir); +#else + home = pw->pw_dir; +#endif + } +#endif + } + + if(!home) + return -1; + + netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC); + if(!netrcfile) { + if(home_alloc) + free(home); + return -1; + } + netrc_alloc = TRUE; + } + + file = fopen(netrcfile, "r"); + if(file) { + char *tok; + char *tok_buf; + bool done=FALSE; + char netrcbuffer[256]; + + while(!done && fgets(netrcbuffer, sizeof(netrcbuffer), file)) { + tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); + while(!done && tok) { + + if (login[0] && password[0]) { + done=TRUE; + break; + } + + switch(state) { + case NOTHING: + if(strequal("machine", tok)) { + /* the next tok is the machine name, this is in itself the + delimiter that starts the stuff entered for this machine, + after this we need to search for 'login' and + 'password'. */ + state=HOSTFOUND; + } + break; + case HOSTFOUND: + if(strequal(host, tok)) { + /* and yes, this is our host! */ + state=HOSTVALID; +#ifdef _NETRC_DEBUG + fprintf(stderr, "HOST: %s\n", tok); +#endif + retcode=0; /* we did find our host */ + } + else + /* not our host */ + state=NOTHING; + break; + case HOSTVALID: + /* we are now parsing sub-keywords concerning "our" host */ + if(state_login) { + if (specific_login) { + state_our_login = strequal(login, tok); + } + else { + strncpy(login, tok, LOGINSIZE-1); +#ifdef _NETRC_DEBUG + fprintf(stderr, "LOGIN: %s\n", login); +#endif + } + state_login=0; + } + else if(state_password) { + if (state_our_login || !specific_login) { + strncpy(password, tok, PASSWORDSIZE-1); +#ifdef _NETRC_DEBUG + fprintf(stderr, "PASSWORD: %s\n", password); +#endif + } + state_password=0; + } + else if(strequal("login", tok)) + state_login=1; + else if(strequal("password", tok)) + state_password=1; + else if(strequal("machine", tok)) { + /* ok, there's machine here go => */ + state = HOSTFOUND; + state_our_login = FALSE; + } + break; + } /* switch (state) */ + + tok = strtok_r(NULL, " \t\n", &tok_buf); + } /* while (tok) */ + } /* while fgets() */ + + fclose(file); + } + + if(home_alloc) + free(home); + if(netrc_alloc) + free(netrcfile); + + return retcode; +} + +#ifdef _NETRC_DEBUG +int main(int argc, char **argv) +{ + char login[64]=""; + char password[64]=""; + + if(argc<2) + return -1; + + if(0 == ParseNetrc(argv[1], login, password)) { + printf("HOST: %s LOGIN: %s PASSWORD: %s\n", + argv[1], login, password); + } +} + +#endif diff --git a/Utilities/cmcurl/lib/netrc.h b/Utilities/cmcurl/lib/netrc.h new file mode 100644 index 0000000..939c552 --- /dev/null +++ b/Utilities/cmcurl/lib/netrc.h @@ -0,0 +1,34 @@ +#ifndef __NETRC_H +#define __NETRC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +int Curl_parsenetrc(char *host, + char *login, + char *password, + char *filename); + /* Assume: password[0]=0, host[0] != 0. + * If login[0] = 0, search for login and password within a machine section + * in the netrc. + * If login[0] != 0, search for password within machine and login. + */ +#endif diff --git a/Utilities/cmcurl/lib/nwlib.c b/Utilities/cmcurl/lib/nwlib.c new file mode 100644 index 0000000..b0eea56 --- /dev/null +++ b/Utilities/cmcurl/lib/nwlib.c @@ -0,0 +1,300 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "memory.h" +#include "memdebug.h" + +typedef struct +{ + int _errno; + void *twentybytes; +} libthreaddata_t; + +typedef struct +{ + int x; + int y; + int z; + void *tenbytes; + NXKey_t perthreadkey; /* if -1, no key obtained... */ + NXMutex_t *lock; +} libdata_t; + +int gLibId = -1; +void *gLibHandle = (void *) NULL; +rtag_t gAllocTag = (rtag_t) NULL; +NXMutex_t *gLibLock = (NXMutex_t *) NULL; + +/* internal library function prototypes... */ +int DisposeLibraryData ( void * ); +void DisposeThreadData ( void * ); +int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata ); + + +int _NonAppStart( void *NLMHandle, + void *errorScreen, + const char *cmdLine, + const char *loadDirPath, + size_t uninitializedDataLength, + void *NLMFileHandle, + int (*readRoutineP)( int conn, + void *fileHandle, size_t offset, + size_t nbytes, + size_t *bytesRead, + void *buffer ), + size_t customDataOffset, + size_t customDataSize, + int messageCount, + const char **messages ) +{ + NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); + +#ifndef __GNUC__ +#pragma unused(cmdLine) +#pragma unused(loadDirPath) +#pragma unused(uninitializedDataLength) +#pragma unused(NLMFileHandle) +#pragma unused(readRoutineP) +#pragma unused(customDataOffset) +#pragma unused(customDataSize) +#pragma unused(messageCount) +#pragma unused(messages) +#endif + +/* +** Here we process our command line, post errors (to the error screen), +** perform initializations and anything else we need to do before being able +** to accept calls into us. If we succeed, we return non-zero and the NetWare +** Loader will leave us up, otherwise we fail to load and get dumped. +*/ + gAllocTag = AllocateResourceTag(NLMHandle, + " memory allocations", + AllocSignature); + + if (!gAllocTag) { + OutputToScreen(errorScreen, "Unable to allocate resource tag for " + "library memory allocations.\n"); + return -1; + } + + gLibId = register_library(DisposeLibraryData); + + if (gLibId < -1) { + OutputToScreen(errorScreen, "Unable to register library with kernel.\n"); + return -1; + } + + gLibHandle = NLMHandle; + + gLibLock = NXMutexAlloc(0, 0, &liblock); + + if (!gLibLock) { + OutputToScreen(errorScreen, "Unable to allocate library data lock.\n"); + return -1; + } + + return 0; +} + +/* +** Here we clean up any resources we allocated. Resource tags is a big part +** of what we created, but NetWare doesn't ask us to free those. +*/ +void _NonAppStop( void ) +{ + (void) unregister_library(gLibId); + NXMutexFree(gLibLock); +} + +/* +** This function cannot be the first in the file for if the file is linked +** first, then the check-unload function's offset will be nlmname.nlm+0 +** which is how to tell that there isn't one. When the check function is +** first in the linked objects, it is ambiguous. For this reason, we will +** put it inside this file after the stop function. +** +** Here we check to see if it's alright to ourselves to be unloaded. If not, +** we return a non-zero value. Right now, there isn't any reason not to allow +** it. +*/ +int _NonAppCheckUnload( void ) +{ + return 0; +} + +int GetOrSetUpData(int id, libdata_t **appData, + libthreaddata_t **threadData ) +{ + int err; + libdata_t *app_data; + libthreaddata_t *thread_data; + NXKey_t key; + NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0); + + err = 0; + thread_data = (libthreaddata_t *) NULL; + +/* +** Attempt to get our data for the application calling us. This is where we +** store whatever application-specific information we need to carry in support +** of calling applications. +*/ + app_data = (libdata_t *) get_app_data(id); + + if (!app_data) { +/* +** This application hasn't called us before; set up application AND per-thread +** data. Of course, just in case a thread from this same application is calling +** us simultaneously, we better lock our application data-creation mutex. We +** also need to recheck for data after we acquire the lock because WE might be +** that other thread that was too late to create the data and the first thread +** in will have created it. +*/ + NXLock(gLibLock); + + if (!(app_data = (libdata_t *) get_app_data(id))) { + app_data = (libdata_t *) malloc(sizeof(libdata_t)); + + if (app_data) { + memset(app_data, 0, sizeof(libdata_t)); + + app_data->tenbytes = malloc(10); + app_data->lock = NXMutexAlloc(0, 0, &liblock); + + if (!app_data->tenbytes || !app_data->lock) { + if (app_data->lock) + NXMutexFree(app_data->lock); + + free(app_data); + app_data = (libdata_t *) NULL; + err = ENOMEM; + } + + if (app_data) { +/* +** Here we burn in the application data that we were trying to get by calling +** get_app_data(). Next time we call the first function, we'll get this data +** we're just now setting. We also go on here to establish the per-thread data +** for the calling thread, something we'll have to do on each application +** thread the first time it calls us. +*/ + err = set_app_data(gLibId, app_data); + + if (err) { + free(app_data); + app_data = (libdata_t *) NULL; + err = ENOMEM; + } + else { + /* create key for thread-specific data... */ + err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key); + + if (err) /* (no more keys left?) */ + key = -1; + + app_data->perthreadkey = key; + } + } + } + } + + NXUnlock(gLibLock); + } + + if (app_data) { + key = app_data->perthreadkey; + + if (key != -1 /* couldn't create a key? no thread data */ + && !(err = NXKeyGetValue(key, (void **) &thread_data)) + && !thread_data) { +/* +** Allocate the per-thread data for the calling thread. Regardless of whether +** there was already application data or not, this may be the first call by a +** a new thread. The fact that we allocation 20 bytes on a pointer is not very +** important, this just helps to demonstrate that we can have arbitrarily +** complex per-thread data. +*/ + thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t)); + + if (thread_data) { + thread_data->_errno = 0; + thread_data->twentybytes = malloc(20); + + if (!thread_data->twentybytes) { + free(thread_data); + thread_data = (libthreaddata_t *) NULL; + err = ENOMEM; + } + + if ((err = NXKeySetValue(key, thread_data))) { + free(thread_data->twentybytes); + free(thread_data); + thread_data = (libthreaddata_t *) NULL; + } + } + } + } + + if (appData) + *appData = app_data; + + if (threadData) + *threadData = thread_data; + + return err; +} + +int DisposeLibraryData( void *data) +{ + if (data) { + void *tenbytes = ((libdata_t *) data)->tenbytes; + + if (tenbytes) + free(tenbytes); + + free(data); + } + + return 0; +} + +void DisposeThreadData(void *data) +{ + if (data) { + void *twentybytes = ((libthreaddata_t *) data)->twentybytes; + + if (twentybytes) + free(twentybytes); + + free(data); + } +} diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c new file mode 100644 index 0000000..ef91585 --- /dev/null +++ b/Utilities/cmcurl/lib/parsedate.c @@ -0,0 +1,425 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +/* + A brief summary of the date string formats this parser groks: + + RFC 2616 3.3.1 + + Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + + we support dates without week day name: + + 06 Nov 1994 08:49:37 GMT + 06-Nov-94 08:49:37 GMT + Nov 6 08:49:37 1994 + + without the time zone: + + 06 Nov 1994 08:49:37 + 06-Nov-94 08:49:37 + + weird order: + + 1994 Nov 6 08:49:37 (GNU date fails) + GMT 08:49:37 06-Nov-94 Sunday + 94 6 Nov 08:49:37 (GNU date fails) + + time left out: + + 1994 Nov 6 + 06-Nov-94 + Sun Nov 6 94 + + unusual separators: + + 1994.Nov.6 + Sun/Nov/6/94/GMT + + commonly used time zone names: + + Sun, 06 Nov 1994 08:49:37 CET + 06 Nov 1994 08:49:37 EST + + time zones specified using RFC822 style: + + Sun, 12 Sep 2004 15:05:58 -0700 + Sat, 11 Sep 2004 21:32:11 +0200 + + compact numerical date strings: + + 20040912 15:05:58 -0700 + 20040911 +0200 + +*/ +#include "setup.h" +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include /* for strtol() */ +#endif + +#include + +static time_t Curl_parsedate(const char *date); + +const char * const Curl_wkday[] = +{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; +static const char * const weekday[] = +{ "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday", "Sunday" }; +const char * const Curl_month[]= +{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +struct tzinfo { + const char *name; + int offset; /* +/- in minutes */ +}; + +/* Here's a bunch of frequently used time zone names. These were supported + by the old getdate parser. */ +#define tDAYZONE -60 /* offset for daylight savings time */ +static const struct tzinfo tz[]= { + {"GMT", 0}, /* Greenwich Mean */ + {"UTC", 0}, /* Universal (Coordinated) */ + {"WET", 0}, /* Western European */ + {"BST", 0 tDAYZONE}, /* British Summer */ + {"WAT", 60}, /* West Africa */ + {"AST", 240}, /* Atlantic Standard */ + {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */ + {"EST", 300}, /* Eastern Standard */ + {"EDT", 300 tDAYZONE}, /* Eastern Daylight */ + {"CST", 360}, /* Central Standard */ + {"CDT", 360 tDAYZONE}, /* Central Daylight */ + {"MST", 420}, /* Mountain Standard */ + {"MDT", 420 tDAYZONE}, /* Mountain Daylight */ + {"PST", 480}, /* Pacific Standard */ + {"PDT", 480 tDAYZONE}, /* Pacific Daylight */ + {"YST", 540}, /* Yukon Standard */ + {"YDT", 540 tDAYZONE}, /* Yukon Daylight */ + {"HST", 600}, /* Hawaii Standard */ + {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */ + {"CAT", 600}, /* Central Alaska */ + {"AHST", 600}, /* Alaska-Hawaii Standard */ + {"NT", 660}, /* Nome */ + {"IDLW", 720}, /* International Date Line West */ + {"CET", -60}, /* Central European */ + {"MET", -60}, /* Middle European */ + {"MEWT", -60}, /* Middle European Winter */ + {"MEST", -60 tDAYZONE}, /* Middle European Summer */ + {"CEST", -60 tDAYZONE}, /* Central European Summer */ + {"MESZ", -60 tDAYZONE}, /* Middle European Summer */ + {"FWT", -60}, /* French Winter */ + {"FST", -60 tDAYZONE}, /* French Summer */ + {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ + {"WAST", -420}, /* West Australian Standard */ + {"WADT", -420 tDAYZONE}, /* West Australian Daylight */ + {"CCT", -480}, /* China Coast, USSR Zone 7 */ + {"JST", -540}, /* Japan Standard, USSR Zone 8 */ + {"EAST", -600}, /* Eastern Australian Standard */ + {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */ + {"GST", -600}, /* Guam Standard, USSR Zone 9 */ + {"NZT", -720}, /* New Zealand */ + {"NZST", -720}, /* New Zealand Standard */ + {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */ + {"IDLE", -720}, /* International Date Line East */ +}; + +/* returns: + -1 no day + 0 monday - 6 sunday +*/ + +static int checkday(char *check, size_t len) +{ + int i; + const char * const *what; + bool found= FALSE; + if(len > 3) + what = &weekday[0]; + else + what = &Curl_wkday[0]; + for(i=0; i<7; i++) { + if(curl_strequal(check, what[0])) { + found=TRUE; + break; + } + what++; + } + return found?i:-1; +} + +static int checkmonth(char *check) +{ + int i; + const char * const *what; + bool found= FALSE; + + what = &Curl_month[0]; + for(i=0; i<12; i++) { + if(curl_strequal(check, what[0])) { + found=TRUE; + break; + } + what++; + } + return found?i:-1; /* return the offset or -1, no real offset is -1 */ +} + +/* return the time zone offset between GMT and the input one, in number + of seconds or -1 if the timezone wasn't found/legal */ + +static int checktz(char *check) +{ + unsigned int i; + const struct tzinfo *what; + bool found= FALSE; + + what = tz; + for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { + if(curl_strequal(check, what->name)) { + found=TRUE; + break; + } + what++; + } + return found?what->offset*60:-1; +} + +static void skip(const char **date) +{ + /* skip everything that aren't letters or digits */ + while(**date && !ISALNUM(**date)) + (*date)++; +} + +enum assume { + DATE_MDAY, + DATE_YEAR, + DATE_TIME +}; + +static time_t Curl_parsedate(const char *date) +{ + time_t t = 0; + int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ + int monnum=-1; /* month of the year number, 0-11 */ + int mdaynum=-1; /* day of month, 1 - 31 */ + int hournum=-1; + int minnum=-1; + int secnum=-1; + int yearnum=-1; + int tzoff=-1; + struct tm tm; + enum assume dignext = DATE_MDAY; + const char *indate = date; /* save the original pointer */ + int part = 0; /* max 6 parts */ + + while(*date && (part < 6)) { + bool found=FALSE; + + skip(&date); + + if(ISALPHA(*date)) { + /* a name coming up */ + char buf[32]=""; + size_t len; + sscanf(date, "%31[A-Za-z]", buf); + len = strlen(buf); + + if(wdaynum == -1) { + wdaynum = checkday(buf, len); + if(wdaynum != -1) + found = TRUE; + } + if(!found && (monnum == -1)) { + monnum = checkmonth(buf); + if(monnum != -1) + found = TRUE; + } + + if(!found && (tzoff == -1)) { + /* this just must be a time zone string */ + tzoff = checktz(buf); + if(tzoff != -1) + found = TRUE; + } + + if(!found) + return -1; /* bad string */ + + date += len; + } + else if(ISDIGIT(*date)) { + /* a digit */ + int val; + char *end; + if((secnum == -1) && + (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { + /* time stamp! */ + date += 8; + found = TRUE; + } + else { + val = (int)strtol(date, &end, 10); + + if((tzoff == -1) && + ((end - date) == 4) && + (val < 1300) && + (indate< date) && + ((date[-1] == '+' || date[-1] == '-'))) { + /* four digits and a value less than 1300 and it is preceeded with + a plus or minus. This is a time zone indication. */ + found = TRUE; + tzoff = (val/100 * 60 + val%100)*60; + + /* the + and - prefix indicates the local time compared to GMT, + this we need ther reversed math to get what we want */ + tzoff = date[-1]=='+'?-tzoff:tzoff; + } + + if(((end - date) == 8) && + (yearnum == -1) && + (monnum == -1) && + (mdaynum == -1)) { + /* 8 digits, no year, month or day yet. This is YYYYMMDD */ + found = TRUE; + yearnum = val/10000; + monnum = (val%10000)/100-1; /* month is 0 - 11 */ + mdaynum = val%100; + } + + if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { + if((val > 0) && (val<32)) { + mdaynum = val; + found = TRUE; + } + dignext = DATE_YEAR; + } + + if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { + yearnum = val; + found = TRUE; + if(yearnum < 1900) { + if (yearnum > 70) + yearnum += 1900; + else + yearnum += 2000; + } + if(mdaynum == -1) + dignext = DATE_MDAY; + } + + if(!found) + return -1; + + date = end; + } + } + + part++; + } + + if(-1 == secnum) + secnum = minnum = hournum = 0; /* no time, make it zero */ + + if((-1 == mdaynum) || + (-1 == monnum) || + (-1 == yearnum)) + /* lacks vital info, fail */ + return -1; + +#if SIZEOF_TIME_T < 5 + /* 32 bit time_t can only hold dates to the beginning of 2038 */ + if(yearnum > 2037) + return 0x7fffffff; +#endif + + tm.tm_sec = secnum; + tm.tm_min = minnum; + tm.tm_hour = hournum; + tm.tm_mday = mdaynum; + tm.tm_mon = monnum; + tm.tm_year = yearnum - 1900; + tm.tm_wday = 0; + tm.tm_yday = 0; + tm.tm_isdst = 0; + + /* mktime() returns a time_t. time_t is often 32 bits, even on many + architectures that feature 64 bit 'long'. + + Some systems have 64 bit time_t and deal with years beyond 2038. However, + even some of the systems with 64 bit time_t returns -1 for dates beyond + 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) + */ + t = mktime(&tm); + + /* time zone adjust (cast t to int to compare to negative one) */ + if(-1 != (int)t) { + struct tm *gmt; + long delta; + time_t t2; + +#ifdef HAVE_GMTIME_R + /* thread-safe version */ + struct tm keeptime2; + gmt = (struct tm *)gmtime_r(&t, &keeptime2); + if(!gmt) + return -1; /* illegal date/time */ + t2 = mktime(gmt); +#else + /* It seems that at least the MSVC version of mktime() doesn't work + properly if it gets the 'gmt' pointer passed in (which is a pointer + returned from gmtime() pointing to static memory), so instead we copy + the tm struct to a local struct and pass a pointer to that struct as + input to mktime(). */ + struct tm gmt2; + gmt = gmtime(&t); /* use gmtime_r() if available */ + if(!gmt) + return -1; /* illegal date/time */ + gmt2 = *gmt; + t2 = mktime(&gmt2); +#endif + + /* Add the time zone diff (between the given timezone and GMT) and the + diff between the local time zone and GMT. */ + delta = (long)((tzoff!=-1?tzoff:0) + (t - t2)); + + if((delta>0) && (t + delta < t)) + return -1; /* time_t overflow */ + + t += delta; + } + + return t; +} + +time_t curl_getdate(const char *p, const time_t *now) +{ + (void)now; + return Curl_parsedate(p); +} diff --git a/Utilities/cmcurl/lib/parsedate.h b/Utilities/cmcurl/lib/parsedate.h new file mode 100644 index 0000000..b29fe9b --- /dev/null +++ b/Utilities/cmcurl/lib/parsedate.h @@ -0,0 +1,28 @@ +#ifndef __PARSEDATE_H +#define __PARSEDATE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +extern const char * const Curl_wkday[7]; +extern const char * const Curl_month[12]; + +#endif diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c new file mode 100644 index 0000000..5ba829a --- /dev/null +++ b/Utilities/cmcurl/lib/progress.c @@ -0,0 +1,424 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#if defined(__EMX__) +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "progress.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero + byte) */ +static void time2str(char *r, long t) +{ + long h; + if(!t) { + strcpy(r, "--:--:--"); + return; + } + h = (t/3600); + if(h <= 99) { + long m = (t-(h*3600))/60; + long s = (t-(h*3600)-(m*60)); + snprintf(r, 9, "%2ld:%02ld:%02ld",h,m,s); + } + else { + /* this equals to more than 99 hours, switch to a more suitable output + format to fit within the limits. */ + if(h/24 <= 999) + snprintf(r, 9, "%3ldd %02ldh", h/24, h-(h/24)*24); + else + snprintf(r, 9, "%7ldd", h/24); + } +} + +/* The point of this function would be to return a string of the input data, + but never longer than 5 columns (+ one zero byte). + Add suffix k, M, G when suitable... */ +static char *max5data(curl_off_t bytes, char *max5) +{ +#define ONE_KILOBYTE 1024 +#define ONE_MEGABYTE (1024* ONE_KILOBYTE) +#define ONE_GIGABYTE (1024* ONE_MEGABYTE) +#define ONE_TERRABYTE ((curl_off_t)1024* ONE_GIGABYTE) +#define ONE_PETABYTE ((curl_off_t)1024* ONE_TERRABYTE) + + if(bytes < 100000) { + snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes); + } + else if(bytes < (10000*ONE_KILOBYTE)) { + snprintf(max5, 6, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE)); + } + else if(bytes < (100*ONE_MEGABYTE)) { + /* 'XX.XM' is good as long as we're less than 100 megs */ + snprintf(max5, 6, "%2d.%0dM", + (int)(bytes/ONE_MEGABYTE), + (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) ); + } +#if SIZEOF_CURL_OFF_T > 4 + else if(bytes < ( (curl_off_t)10000*ONE_MEGABYTE)) + /* 'XXXXM' is good until we're at 10000MB or above */ + snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE)); + + else if(bytes < (curl_off_t)100*ONE_GIGABYTE) + /* 10000 MB - 100 GB, we show it as XX.XG */ + snprintf(max5, 6, "%2d.%0dG", + (int)(bytes/ONE_GIGABYTE), + (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) ); + + else if(bytes < (curl_off_t)10000 * ONE_GIGABYTE) + /* up to 10000GB, display without decimal: XXXXG */ + snprintf(max5, 6, "%4dG", (int)(bytes/ONE_GIGABYTE)); + + else if(bytes < (curl_off_t)10000 * ONE_TERRABYTE) + /* up to 10000TB, display without decimal: XXXXT */ + snprintf(max5, 6, "%4dT", (int)(bytes/ONE_TERRABYTE)); + else { + /* up to 10000PB, display without decimal: XXXXP */ + snprintf(max5, 6, "%4dP", (int)(bytes/ONE_PETABYTE)); + + /* 16384 petabytes (16 exabytes) is maximum a 64 bit number can hold, + but this type is signed so 8192PB will be max.*/ + } + +#else + else + snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE)); +#endif + + return max5; +} + +/* + + New proposed interface, 9th of February 2000: + + pgrsStartNow() - sets start time + pgrsSetDownloadSize(x) - known expected download size + pgrsSetUploadSize(x) - known expected upload size + pgrsSetDownloadCounter() - amount of data currently downloaded + pgrsSetUploadCounter() - amount of data currently uploaded + pgrsUpdate() - show progress + pgrsDone() - transfer complete + +*/ + +void Curl_pgrsDone(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + data->progress.lastshow=0; + Curl_pgrsUpdate(conn); /* the final (forced) update */ + + data->progress.speeder_c = 0; /* reset the progress meter display */ +} + +/* reset all times except redirect */ +void Curl_pgrsResetTimes(struct SessionHandle *data) +{ + data->progress.t_nslookup = 0.0; + data->progress.t_connect = 0.0; + data->progress.t_pretransfer = 0.0; + data->progress.t_starttransfer = 0.0; +} + +void Curl_pgrsTime(struct SessionHandle *data, timerid timer) +{ + switch(timer) { + default: + case TIMER_NONE: + /* mistake filter */ + break; + case TIMER_STARTSINGLE: + /* This is set at the start of a single fetch */ + data->progress.t_startsingle = Curl_tvnow(); + break; + + case TIMER_NAMELOOKUP: + data->progress.t_nslookup = + Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + break; + case TIMER_CONNECT: + data->progress.t_connect = + Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + break; + case TIMER_PRETRANSFER: + data->progress.t_pretransfer = + Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + break; + case TIMER_STARTTRANSFER: + data->progress.t_starttransfer = + Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + break; + case TIMER_POSTRANSFER: + /* this is the normal end-of-transfer thing */ + break; + case TIMER_REDIRECT: + data->progress.t_redirect = + Curl_tvdiff_secs(Curl_tvnow(), data->progress.start); + break; + } +} + +void Curl_pgrsStartNow(struct SessionHandle *data) +{ + data->progress.speeder_c = 0; /* reset the progress meter display */ + data->progress.start = Curl_tvnow(); +} + +void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) +{ + data->progress.downloaded = size; +} + +void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size) +{ + data->progress.uploaded = size; +} + +void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) +{ + data->progress.size_dl = size; + if(size > 0) + data->progress.flags |= PGRS_DL_SIZE_KNOWN; + else + data->progress.flags &= ~PGRS_DL_SIZE_KNOWN; +} + +void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size) +{ + data->progress.size_ul = size; + if(size > 0) + data->progress.flags |= PGRS_UL_SIZE_KNOWN; + else + data->progress.flags &= ~PGRS_UL_SIZE_KNOWN; +} + +int Curl_pgrsUpdate(struct connectdata *conn) +{ + struct timeval now; + int result; + char max5[6][10]; + int dlpercen=0; + int ulpercen=0; + int total_percen=0; + curl_off_t total_transfer; + curl_off_t total_expected_transfer; + long timespent; + struct SessionHandle *data = conn->data; + int nowindex = data->progress.speeder_c% CURR_TIME; + int checkindex; + int countindex; /* amount of seconds stored in the speeder array */ + char time_left[10]; + char time_total[10]; + char time_spent[10]; + long ulestimate=0; + long dlestimate=0; + long total_estimate; + + if(data->progress.flags & PGRS_HIDE) + ; /* We do enter this function even if we don't wanna see anything, since + this is were lots of the calculations are being made that will be used + even when not displayed! */ + else if(!(data->progress.flags & PGRS_HEADERS_OUT)) { + if (!data->progress.callback) { + if(data->reqdata.resume_from) + fprintf(data->set.err, + "** Resuming transfer from byte position %" FORMAT_OFF_T + "\n", + data->reqdata.resume_from); + fprintf(data->set.err, + " %% Total %% Received %% Xferd Average Speed Time Time Time Current\n" + " Dload Upload Total Spent Left Speed\n"); + } + data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */ + } + + now = Curl_tvnow(); /* what time is it */ + + /* The time spent so far (from the start) */ + data->progress.timespent = Curl_tvdiff_secs(now, data->progress.start); + timespent = (long)data->progress.timespent; + + /* The average download speed this far */ + data->progress.dlspeed = (curl_off_t) + ((double)data->progress.downloaded/ + (data->progress.timespent>0?data->progress.timespent:1)); + + /* The average upload speed this far */ + data->progress.ulspeed = (curl_off_t) + ((double)data->progress.uploaded/ + (data->progress.timespent>0?data->progress.timespent:1)); + + if(data->progress.lastshow == Curl_tvlong(now)) + return 0; /* never update this more than once a second if the end isn't + reached */ + data->progress.lastshow = now.tv_sec; + + /* Let's do the "current speed" thing, which should use the fastest + of the dl/ul speeds. Store the fasted speed at entry 'nowindex'. */ + data->progress.speeder[ nowindex ] = + data->progress.downloaded>data->progress.uploaded? + data->progress.downloaded:data->progress.uploaded; + + /* remember the exact time for this moment */ + data->progress.speeder_time [ nowindex ] = now; + + /* advance our speeder_c counter, which is increased every time we get + here and we expect it to never wrap as 2^32 is a lot of seconds! */ + data->progress.speeder_c++; + + /* 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've filled in three entries etc. */ + countindex = ((data->progress.speeder_c>=CURR_TIME)? + CURR_TIME:data->progress.speeder_c) - 1; + + /* first of all, we don't do this if there's no counted seconds yet */ + if(countindex) { + long span_ms; + + /* Get the index position to compare with the 'nowindex' position. + Get the oldest entry possible. While we have less than CURR_TIME + entries, the first entry will remain the oldest. */ + checkindex = (data->progress.speeder_c>=CURR_TIME)? + data->progress.speeder_c%CURR_TIME:0; + + /* Figure out the exact time for the time span */ + span_ms = Curl_tvdiff(now, + data->progress.speeder_time[checkindex]); + if(0 == span_ms) + span_ms=1; /* at least one millisecond MUST have passed */ + + /* Calculate the average speed the last 'span_ms' milliseconds */ + { + curl_off_t amount = data->progress.speeder[nowindex]- + data->progress.speeder[checkindex]; + + if(amount > 4294967 /* 0xffffffff/1000 */) + /* the 'amount' value is bigger than would fit in 32 bits if + multiplied with 1000, so we use the double math for this */ + data->progress.current_speed = (curl_off_t) + ((double)amount/((double)span_ms/1000.0)); + else + /* the 'amount' value is small enough to fit within 32 bits even + when multiplied with 1000 */ + data->progress.current_speed = amount*1000/span_ms; + } + } + else + /* the first second we use the main average */ + data->progress.current_speed = + (data->progress.ulspeed>data->progress.dlspeed)? + data->progress.ulspeed:data->progress.dlspeed; + + if(data->progress.flags & PGRS_HIDE) + return 0; + + else if(data->set.fprogress) { + /* There's a callback set, so we call that instead of writing + anything ourselves. This really is the way to go. */ + result= data->set.fprogress(data->set.progress_client, + (double)data->progress.size_dl, + (double)data->progress.downloaded, + (double)data->progress.size_ul, + (double)data->progress.uploaded); + if(result) + failf(data, "Callback aborted"); + return result; + } + + /* Figure out the estimated time of arrival for the upload */ + if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && + (data->progress.ulspeed>0) && + (data->progress.size_ul > 100) ) { + ulestimate = (long)(data->progress.size_ul / data->progress.ulspeed); + ulpercen = (int)(100*(data->progress.uploaded/100) / + (data->progress.size_ul/100) ); + } + + /* ... and the download */ + if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && + (data->progress.dlspeed>0) && + (data->progress.size_dl>100)) { + dlestimate = (long)(data->progress.size_dl / data->progress.dlspeed); + dlpercen = (int)(100*(data->progress.downloaded/100) / + (data->progress.size_dl/100)); + } + + /* Now figure out which of them that is slower and use for the for + total estimate! */ + total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; + + /* create the three time strings */ + 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 transfered */ + 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 transfered this much so far */ + total_transfer = data->progress.downloaded + data->progress.uploaded; + + /* Get the percentage of data transfered so far */ + if(total_expected_transfer > 100) + total_percen=(int)(100*(total_transfer/100) / + (total_expected_transfer/100) ); + + fprintf(data->set.err, + "\r%3d %s %3d %s %3d %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(data->progress.current_speed, max5[5]) /* current speed */ + ); + + /* we flush the output stream to make it appear as soon as possible */ + fflush(data->set.err); + + return 0; +} diff --git a/Utilities/cmcurl/lib/progress.h b/Utilities/cmcurl/lib/progress.h new file mode 100644 index 0000000..ad9d662 --- /dev/null +++ b/Utilities/cmcurl/lib/progress.h @@ -0,0 +1,70 @@ +#ifndef __PROGRESS_H +#define __PROGRESS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "timeval.h" + + +typedef enum { + TIMER_NONE, + TIMER_NAMELOOKUP, + TIMER_CONNECT, + TIMER_PRETRANSFER, + TIMER_STARTTRANSFER, + TIMER_POSTRANSFER, + TIMER_STARTSINGLE, + TIMER_REDIRECT, + TIMER_LAST /* must be last */ +} timerid; + +void Curl_pgrsDone(struct connectdata *); +void Curl_pgrsStartNow(struct SessionHandle *data); +void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size); +void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size); +void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size); +void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size); +int Curl_pgrsUpdate(struct connectdata *); +void Curl_pgrsResetTimes(struct SessionHandle *data); +void Curl_pgrsTime(struct SessionHandle *data, timerid timer); + + +/* Don't show progress for sizes smaller than: */ +#define LEAST_SIZE_PROGRESS BUFSIZE + +#define PROGRESS_DOWNLOAD (1<<0) +#define PROGRESS_UPLOAD (1<<1) +#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD) + +#define PGRS_SHOW_DL (1<<0) +#define PGRS_SHOW_UL (1<<1) +#define PGRS_DONE_DL (1<<2) +#define PGRS_DONE_UL (1<<3) +#define PGRS_HIDE (1<<4) +#define PGRS_UL_SIZE_KNOWN (1<<5) +#define PGRS_DL_SIZE_KNOWN (1<<6) + +#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */ + + +#endif /* __PROGRESS_H */ diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c new file mode 100644 index 0000000..4c9aed8 --- /dev/null +++ b/Utilities/cmcurl/lib/security.c @@ -0,0 +1,493 @@ +/* This source code was modified by Martin Hedenfalk for + * use in Curl. His latest changes were done 2000-09-18. + * + * It has since been patched and modified a lot by Daniel Stenberg + * to make it better applied to curl conditions, and to make + * it not use globals, pollute name space and more. This source code awaits a + * rewrite to work around the paragraph 2 in the BSD licenses as explained + * below. + * + * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * 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. */ + +#include "setup.h" + +#ifndef CURL_DISABLE_FTP +#ifdef HAVE_KRB4 + +#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */ +#include + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "urldata.h" +#include "krb4.h" +#include "base64.h" +#include "sendf.h" +#include "ftp.h" +#include "memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +static const struct { + enum protection_level level; + const char *name; +} level_names[] = { + { prot_clear, "clear" }, + { prot_safe, "safe" }, + { prot_confidential, "confidential" }, + { prot_private, "private" } +}; + +static enum protection_level +name_to_level(const char *name) +{ + int i; + for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) + if(curl_strnequal(level_names[i].name, name, strlen(name))) + return level_names[i].level; + return (enum protection_level)-1; +} + +static const struct Curl_sec_client_mech * const mechs[] = { +#ifdef KRB5 + /* not supported */ +#endif +#ifdef HAVE_KRB4 + &Curl_krb4_client_mech, +#endif + NULL +}; + +int +Curl_sec_getc(struct connectdata *conn, FILE *F) +{ + if(conn->sec_complete && conn->data_prot) { + char c; + if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0) + return EOF; + return c; + } + else + return getc(F); +} + +static int +block_read(int fd, void *buf, size_t len) +{ + unsigned char *p = buf; + int b; + while(len) { + b = read(fd, p, len); + if (b == 0) + return 0; + else if (b < 0) + return -1; + len -= b; + p += b; + } + return p - (unsigned char*)buf; +} + +static int +block_write(int fd, void *buf, size_t len) +{ + unsigned char *p = buf; + int b; + while(len) { + b = write(fd, p, len); + if(b < 0) + return -1; + len -= b; + p += b; + } + return p - (unsigned char*)buf; +} + +static int +sec_get_data(struct connectdata *conn, + int fd, struct krb4buffer *buf) +{ + int len; + int b; + + b = block_read(fd, &len, sizeof(len)); + if (b == 0) + return 0; + else if (b < 0) + return -1; + len = ntohl(len); + buf->data = realloc(buf->data, len); + b = block_read(fd, buf->data, len); + if (b == 0) + return 0; + else if (b < 0) + return -1; + buf->size = (conn->mech->decode)(conn->app_data, buf->data, len, + conn->data_prot, conn); + buf->index = 0; + return 0; +} + +static size_t +buffer_read(struct krb4buffer *buf, void *data, size_t len) +{ + len = min(len, buf->size - buf->index); + memcpy(data, (char*)buf->data + buf->index, len); + buf->index += len; + return len; +} + +static size_t +buffer_write(struct krb4buffer *buf, void *data, size_t len) +{ + if(buf->index + len > buf->size) { + void *tmp; + if(buf->data == NULL) + tmp = malloc(1024); + else + tmp = realloc(buf->data, buf->index + len); + if(tmp == NULL) + return -1; + buf->data = tmp; + buf->size = buf->index + len; + } + memcpy((char*)buf->data + buf->index, data, len); + buf->index += len; + return len; +} + +int +Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length) +{ + size_t len; + int rx = 0; + + if(conn->sec_complete == 0 || conn->data_prot == 0) + return read(fd, buffer, length); + + if(conn->in_buffer.eof_flag){ + conn->in_buffer.eof_flag = 0; + return 0; + } + + len = buffer_read(&conn->in_buffer, buffer, length); + length -= len; + rx += len; + buffer = (char*)buffer + len; + + while(length) { + if(sec_get_data(conn, fd, &conn->in_buffer) < 0) + return -1; + if(conn->in_buffer.size == 0) { + if(rx) + conn->in_buffer.eof_flag = 1; + return rx; + } + len = buffer_read(&conn->in_buffer, buffer, length); + length -= len; + rx += len; + buffer = (char*)buffer + len; + } + return rx; +} + +static int +sec_send(struct connectdata *conn, int fd, char *from, int length) +{ + int bytes; + void *buf; + bytes = (conn->mech->encode)(conn->app_data, from, length, conn->data_prot, + &buf, conn); + bytes = htonl(bytes); + block_write(fd, &bytes, sizeof(bytes)); + block_write(fd, buf, ntohl(bytes)); + free(buf); + return length; +} + +int +Curl_sec_fflush_fd(struct connectdata *conn, int fd) +{ + if(conn->data_prot != prot_clear) { + if(conn->out_buffer.index > 0){ + Curl_sec_write(conn, fd, + conn->out_buffer.data, conn->out_buffer.index); + conn->out_buffer.index = 0; + } + sec_send(conn, fd, NULL, 0); + } + return 0; +} + +int +Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length) +{ + int len = conn->buffer_size; + int tx = 0; + + if(conn->data_prot == prot_clear) + return write(fd, buffer, length); + + len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len); + while(length){ + if(length < len) + len = length; + sec_send(conn, fd, buffer, len); + length -= len; + buffer += len; + tx += len; + } + return tx; +} + +ssize_t +Curl_sec_send(struct connectdata *conn, int num, char *buffer, int length) +{ + curl_socket_t fd = conn->sock[num]; + return (ssize_t)Curl_sec_write(conn, fd, buffer, length); +} + +int +Curl_sec_putc(struct connectdata *conn, int c, FILE *F) +{ + char ch = c; + if(conn->data_prot == prot_clear) + return putc(c, F); + + buffer_write(&conn->out_buffer, &ch, 1); + if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) { + Curl_sec_write(conn, fileno(F), conn->out_buffer.data, + conn->out_buffer.index); + conn->out_buffer.index = 0; + } + return c; +} + +int +Curl_sec_read_msg(struct connectdata *conn, char *s, int level) +{ + int len; + unsigned char *buf; + int code; + + len = Curl_base64_decode(s + 4, &buf); /* XXX */ + if(len > 0) + len = (conn->mech->decode)(conn->app_data, buf, len, level, conn); + else + return -1; + + if(len < 0) { + free(buf); + return -1; + } + + buf[len] = '\0'; + + if(buf[3] == '-') + code = 0; + else + sscanf((char *)buf, "%d", &code); + if(buf[len-1] == '\n') + buf[len-1] = '\0'; + strcpy(s, (char *)buf); + free(buf); + return code; +} + +enum protection_level +Curl_set_command_prot(struct connectdata *conn, enum protection_level level) +{ + enum protection_level old = conn->command_prot; + conn->command_prot = level; + return old; +} + +static int +sec_prot_internal(struct connectdata *conn, int level) +{ + char *p; + unsigned int s = 1048576; + ssize_t nread; + + if(!conn->sec_complete){ + infof(conn->data, "No security data exchange has taken place.\n"); + return -1; + } + + if(level){ + int code; + if(Curl_ftpsendf(conn, "PBSZ %u", s)) + return -1; + + if(Curl_GetFTPResponse(&nread, conn, &code)) + return -1; + + if(code/100 != '2'){ + failf(conn->data, "Failed to set protection buffer size."); + return -1; + } + conn->buffer_size = s; + + p = strstr(conn->data->state.buffer, "PBSZ="); + if(p) + sscanf(p, "PBSZ=%u", &s); + if(s < conn->buffer_size) + conn->buffer_size = s; + } + + if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"])) + return -1; + + if(Curl_GetFTPResponse(&nread, conn, NULL)) + return -1; + + if(conn->data->state.buffer[0] != '2'){ + failf(conn->data, "Failed to set protection level."); + return -1; + } + + conn->data_prot = (enum protection_level)level; + return 0; +} + +void +Curl_sec_set_protection_level(struct connectdata *conn) +{ + if(conn->sec_complete && conn->data_prot != conn->request_data_prot) + sec_prot_internal(conn, conn->request_data_prot); +} + + +int +Curl_sec_request_prot(struct connectdata *conn, const char *level) +{ + int l = name_to_level(level); + if(l == -1) + return -1; + conn->request_data_prot = (enum protection_level)l; + return 0; +} + +int +Curl_sec_login(struct connectdata *conn) +{ + int ret; + const struct Curl_sec_client_mech * const *m; + ssize_t nread; + struct SessionHandle *data=conn->data; + int ftpcode; + + for(m = mechs; *m && (*m)->name; m++) { + void *tmp; + + tmp = realloc(conn->app_data, (*m)->size); + if (tmp == NULL) { + failf (data, "realloc %u failed", (*m)->size); + return -1; + } + conn->app_data = tmp; + + if((*m)->init && (*(*m)->init)(conn->app_data) != 0) { + infof(data, "Skipping %s...\n", (*m)->name); + continue; + } + infof(data, "Trying %s...\n", (*m)->name); + + if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name)) + return -1; + + if(Curl_GetFTPResponse(&nread, conn, &ftpcode)) + return -1; + + if(conn->data->state.buffer[0] != '3'){ + switch(ftpcode) { + case 504: + infof(data, + "%s is not supported by the server.\n", (*m)->name); + break; + case 534: + infof(data, "%s rejected as security mechanism.\n", (*m)->name); + break; + default: + if(conn->data->state.buffer[0] == '5') { + infof(data, "The server doesn't support the FTP " + "security extensions.\n"); + return -1; + } + break; + } + continue; + } + + ret = (*(*m)->auth)(conn->app_data, conn); + + if(ret == AUTH_CONTINUE) + continue; + else if(ret != AUTH_OK){ + /* mechanism is supposed to output error string */ + return -1; + } + conn->mech = *m; + conn->sec_complete = 1; + conn->command_prot = prot_safe; + break; + } + + return *m == NULL; +} + +void +Curl_sec_end(struct connectdata *conn) +{ + if (conn->mech != NULL) { + if(conn->mech->end) + (conn->mech->end)(conn->app_data); + memset(conn->app_data, 0, conn->mech->size); + free(conn->app_data); + conn->app_data = NULL; + } + conn->sec_complete = 0; + conn->data_prot = (enum protection_level)0; + conn->mech=NULL; +} + +#endif /* HAVE_KRB4 */ +#endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c new file mode 100644 index 0000000..82f9dc2 --- /dev/null +++ b/Utilities/cmcurl/lib/select.c @@ -0,0 +1,315 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifndef HAVE_SELECT +#error "We can't compile without select() support!" +#endif + +#if defined(__BEOS__) +/* BeOS has FD_SET defined in socket.h */ +#include +#endif + +#ifdef __MSDOS__ +#include /* delay() */ +#endif + +#include + +#include "urldata.h" +#include "connect.h" +#include "select.h" + +#if defined(USE_WINSOCK) || defined(TPF) +#define VERIFY_SOCK(x) /* sockets are not in range [0..FD_SETSIZE] */ +#else +#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x)) { \ + errno = EINVAL; \ + return -1; \ + } \ +} while(0) +#endif + +/* + * This is an internal function used for waiting for read or write + * events on single file descriptors. It attempts to replace select() + * in order to avoid limits with FD_SETSIZE. + * + * Return values: + * -1 = system call error + * 0 = timeout + * CSELECT_IN | CSELECT_OUT | CSELECT_ERR + */ +int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms) +{ +#if (defined(HAVE_POLL) && !defined(_POLL_EMUL_H_)) || defined(CURL_HAVE_WSAPOLL) + struct pollfd pfd[2]; + int num; + int r; + int ret; + + num = 0; + if (readfd != CURL_SOCKET_BAD) { + pfd[num].fd = readfd; + pfd[num].events = POLLIN; + num++; + } + if (writefd != CURL_SOCKET_BAD) { + pfd[num].fd = writefd; + pfd[num].events = POLLOUT; + num++; + } + +#if defined(HAVE_POLL) && !defined(_POLL_EMUL_H_) + do { + r = poll(pfd, num, timeout_ms); + } while((r == -1) && (errno == EINTR)); +#else + r = WSAPoll(pfd, num, timeout_ms); +#endif + + if (r < 0) + return -1; + if (r == 0) + return 0; + + ret = 0; + num = 0; + if (readfd != CURL_SOCKET_BAD) { + if (pfd[num].revents & (POLLIN|POLLHUP)) + ret |= CSELECT_IN; + if (pfd[num].revents & POLLERR) { +#ifdef __CYGWIN__ + /* Cygwin 1.5.21 needs this hack to pass test 160 */ + if (errno == EINPROGRESS) + ret |= CSELECT_IN; + else +#endif + ret |= CSELECT_ERR; + } + num++; + } + if (writefd != CURL_SOCKET_BAD) { + if (pfd[num].revents & POLLOUT) + ret |= CSELECT_OUT; + if (pfd[num].revents & (POLLERR|POLLHUP)) + ret |= CSELECT_ERR; + } + + return ret; +#else + struct timeval timeout; + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + curl_socket_t maxfd; + int r; + int ret; + + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + + if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { + /* According to POSIX we should pass in NULL pointers if we don't want to + wait for anything in particular but just use the timeout function. + Windows however returns immediately if done so. I copied the MSDOS + delay() use from src/main.c that already had this work-around. */ +#ifdef WIN32 + Sleep(timeout_ms); +#elif defined(__MSDOS__) + delay(timeout_ms); +#else + select(0, NULL, NULL, NULL, &timeout); +#endif + return 0; + } + + FD_ZERO(&fds_err); + maxfd = (curl_socket_t)-1; + + FD_ZERO(&fds_read); + if (readfd != CURL_SOCKET_BAD) { + VERIFY_SOCK(readfd); + FD_SET(readfd, &fds_read); + FD_SET(readfd, &fds_err); + maxfd = readfd; + } + + FD_ZERO(&fds_write); + if (writefd != CURL_SOCKET_BAD) { + VERIFY_SOCK(writefd); + FD_SET(writefd, &fds_write); + FD_SET(writefd, &fds_err); + if (writefd > maxfd) + maxfd = writefd; + } + + do { + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); + } while((r == -1) && (Curl_sockerrno() == EINTR)); + + if (r < 0) + return -1; + if (r == 0) + return 0; + + ret = 0; + if (readfd != CURL_SOCKET_BAD) { + if (FD_ISSET(readfd, &fds_read)) + ret |= CSELECT_IN; + if (FD_ISSET(readfd, &fds_err)) + ret |= CSELECT_ERR; + } + if (writefd != CURL_SOCKET_BAD) { + if (FD_ISSET(writefd, &fds_write)) + ret |= CSELECT_OUT; + if (FD_ISSET(writefd, &fds_err)) + ret |= CSELECT_ERR; + } + + return ret; +#endif +} + +/* + * 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 too large for FD_SETSIZE. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * 1 = number of structures with non zero revent fields + */ +int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) +{ + int r; +#if defined(HAVE_POLL) && !defined(_POLL_EMUL_H_) + do { + r = poll(ufds, nfds, timeout_ms); + } while((r == -1) && (errno == EINTR)); +#elif defined(CURL_HAVE_WSAPOLL) + r = WSAPoll(ufds, nfds, timeout_ms); +#else + struct timeval timeout; + struct timeval *ptimeout; + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + curl_socket_t maxfd; + unsigned int i; + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_ZERO(&fds_err); + maxfd = (curl_socket_t)-1; + + for (i = 0; i < nfds; i++) { + if (ufds[i].fd == CURL_SOCKET_BAD) + continue; +#ifndef USE_WINSOCK /* winsock sockets are not in range [0..FD_SETSIZE] */ + if (ufds[i].fd >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } +#endif + if (ufds[i].fd > maxfd) + maxfd = ufds[i].fd; + if (ufds[i].events & POLLIN) + FD_SET(ufds[i].fd, &fds_read); + if (ufds[i].events & POLLOUT) + FD_SET(ufds[i].fd, &fds_write); + if (ufds[i].events & POLLERR) + FD_SET(ufds[i].fd, &fds_err); + } + + if (timeout_ms < 0) { + ptimeout = NULL; /* wait forever */ + } else { + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + ptimeout = &timeout; + } + + do { + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); + } while((r == -1) && (Curl_sockerrno() == EINTR)); + + if (r < 0) + return -1; + if (r == 0) + return 0; + + r = 0; + for (i = 0; i < nfds; i++) { + ufds[i].revents = 0; + if (ufds[i].fd == CURL_SOCKET_BAD) + continue; + if (FD_ISSET(ufds[i].fd, &fds_read)) + ufds[i].revents |= POLLIN; + if (FD_ISSET(ufds[i].fd, &fds_write)) + ufds[i].revents |= POLLOUT; + if (FD_ISSET(ufds[i].fd, &fds_err)) + ufds[i].revents |= POLLERR; + if (ufds[i].revents != 0) + r++; + } +#endif + return r; +} + +#ifdef TPF +/* + * This is a replacement for select() on the TPF platform. + * It is used whenever libcurl calls select(). + * The call below to tpf_process_signals() is required because + * TPF's select calls are not signal interruptible. + * + * Return values are the same as select's. + */ +int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, + fd_set* excepts, struct timeval* tv) +{ + int rc; + + rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); + tpf_process_signals(); + return(rc); +} +#endif /* TPF */ diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h new file mode 100644 index 0000000..7573b1f --- /dev/null +++ b/Utilities/cmcurl/lib/select.h @@ -0,0 +1,60 @@ +#ifndef __SELECT_H +#define __SELECT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifdef HAVE_SYS_POLL_H +#include +#else +#ifndef POLLIN +#define POLLIN 0x01 +#define POLLPRI 0x02 +#define POLLOUT 0x04 +#define POLLERR 0x08 +#define POLLHUP 0x10 +#define POLLNVAL 0x20 + +struct pollfd +{ + curl_socket_t fd; + short events; + short revents; +}; +#endif + +#endif + +#define CSELECT_IN 0x01 +#define CSELECT_OUT 0x02 +#define CSELECT_ERR 0x04 + +int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms); + +int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); + +#ifdef TPF +int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, + fd_set* excepts, struct timeval* tv); +#endif + +#endif diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c new file mode 100644 index 0000000..500bf66 --- /dev/null +++ b/Utilities/cmcurl/lib/sendf.c @@ -0,0 +1,663 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include /* required for send() & recv() prototypes */ +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "connect.h" /* for the Curl_sockerrno() proto */ +#include "sslgen.h" +#include "ssh.h" +#include "multiif.h" + +#define _MPRINTF_REPLACE /* use the internal *printf() functions */ +#include + +#ifdef HAVE_KRB4 +#include "krb4.h" +#else +#define Curl_sec_send(a,b,c,d) -1 +#define Curl_sec_read(a,b,c,d) -1 +#endif + +#include +#include "memory.h" +#include "strerror.h" +#include "easyif.h" /* for the Curl_convert_from_network prototype */ +/* The last #include file should be: */ +#include "memdebug.h" + +/* returns last node in linked list */ +static struct curl_slist *slist_get_last(struct curl_slist *list) +{ + struct curl_slist *item; + + /* if caller passed us a NULL, return now */ + if (!list) + return NULL; + + /* loop through to find the last item */ + item = list; + while (item->next) { + item = item->next; + } + return item; +} + +/* + * curl_slist_append() appends a string to the linked list. It always retunrs + * the address of the first record, so that you can sure this function as an + * initialization function as well as an append function. If you find this + * bothersome, then simply create a separate _init function and call it + * appropriately from within the proram. + */ +struct curl_slist *curl_slist_append(struct curl_slist *list, + const char *data) +{ + struct curl_slist *last; + struct curl_slist *new_item; + + new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist)); + if (new_item) { + char *dup = strdup(data); + if(dup) { + new_item->next = NULL; + new_item->data = dup; + } + else { + free(new_item); + return NULL; + } + } + else + return NULL; + + if (list) { + last = slist_get_last(list); + last->next = new_item; + return list; + } + + /* if this is the first item, then new_item *is* the list */ + return new_item; +} + +/* be nice and clean up resources */ +void curl_slist_free_all(struct curl_slist *list) +{ + struct curl_slist *next; + struct curl_slist *item; + + if (!list) + return; + + item = list; + do { + next = item->next; + + if (item->data) { + free(item->data); + } + free(item); + item = next; + } while (next); +} + +#ifdef CURL_DO_LINEEND_CONV +/* + * 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 SessionHandle *data, + char *startPtr, size_t size) +{ + char *inPtr, *outPtr; + + /* sanity check */ + if ((startPtr == NULL) || (size < 1)) { + return(size); + } + + if (data->state.prev_block_had_trailing_cr == TRUE) { + /* 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 */ + memcpy(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++; + inPtr++; + } + 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_infof() is for info message along the way */ + +void Curl_infof(struct SessionHandle *data, const char *fmt, ...) +{ + if(data && data->set.verbose) { + va_list ap; + size_t len; + char print_buffer[1024 + 1]; + va_start(ap, fmt); + vsnprintf(print_buffer, 1024, fmt, ap); + va_end(ap); + len = strlen(print_buffer); + Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL); + } +} + +/* Curl_failf() is for messages stating why we failed. + * The message SHALL NOT include any LF or CR. + */ + +void Curl_failf(struct SessionHandle *data, const char *fmt, ...) +{ + va_list ap; + size_t len; + va_start(ap, fmt); + + vsnprintf(data->state.buffer, BUFSIZE, fmt, ap); + + if(data->set.errorbuffer && !data->state.errorbuf) { + snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer); + data->state.errorbuf = TRUE; /* wrote error string */ + } + if(data->set.verbose) { + len = strlen(data->state.buffer); + if(len < BUFSIZE - 1) { + data->state.buffer[len] = '\n'; + data->state.buffer[++len] = '\0'; + } + Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL); + } + + va_end(ap); +} + +/* Curl_sendf() sends formated data to the server */ +CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, + const char *fmt, ...) +{ + struct SessionHandle *data = conn->data; + ssize_t bytes_written; + size_t write_len; + CURLcode res = CURLE_OK; + char *s; + char *sptr; + va_list ap; + va_start(ap, fmt); + s = vaprintf(fmt, ap); /* returns an allocated string */ + va_end(ap); + if(!s) + return CURLE_OUT_OF_MEMORY; /* failure */ + + bytes_written=0; + write_len = strlen(s); + sptr = s; + + while (1) { + /* Write the buffer to the socket */ + res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); + + if(CURLE_OK != res) + break; + + if(data->set.verbose) + Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn); + + if((size_t)bytes_written != write_len) { + /* if not all was written at once, we must advance the pointer, decrease + the size left and try again! */ + write_len -= bytes_written; + sptr += bytes_written; + } + else + break; + } + + free(s); /* free the output string */ + + return res; +} + +static ssize_t Curl_plain_send(struct connectdata *conn, + int num, + void *mem, + size_t len) +{ + curl_socket_t sockfd = conn->sock[num]; + ssize_t bytes_written = swrite(sockfd, mem, len); + + if(-1 == bytes_written) { + int err = Curl_sockerrno(); + + if( +#ifdef WSAEWOULDBLOCK + /* This is how Windows does it */ + (WSAEWOULDBLOCK == err) +#else + /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned + due to its inability to send off data without blocking. We therefor + treat both error codes the same here */ + (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) +#endif + ) + /* this is just a case of EWOULDBLOCK */ + bytes_written=0; + else + failf(conn->data, "Send failure: %s", + Curl_strerror(conn, err)); + } + return bytes_written; +} + +/* + * Curl_write() is an internal write function that sends data to the + * server. Works with plain sockets, SCP, SSL or kerberos. + */ +CURLcode Curl_write(struct connectdata *conn, + curl_socket_t sockfd, + void *mem, + size_t len, + ssize_t *written) +{ + ssize_t bytes_written; + CURLcode retcode; + int num = (sockfd == conn->sock[SECONDARYSOCKET]); + + if (conn->ssl[num].use) + /* only TRUE if SSL enabled */ + bytes_written = Curl_ssl_send(conn, num, mem, len); +#ifdef USE_LIBSSH2 + else if (conn->protocol & PROT_SCP) + bytes_written = Curl_scp_send(conn, num, mem, len); + else if (conn->protocol & PROT_SFTP) + bytes_written = Curl_sftp_send(conn, num, mem, len); +#endif /* !USE_LIBSSH2 */ + else if(conn->sec_complete) + /* only TRUE if krb4 enabled */ + bytes_written = Curl_sec_send(conn, num, mem, len); + else + bytes_written = Curl_plain_send(conn, num, mem, len); + + *written = bytes_written; + retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR; + + return retcode; +} + +/* 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. + */ +CURLcode Curl_client_write(struct connectdata *conn, + int type, + char *ptr, + size_t len) +{ + struct SessionHandle *data = conn->data; + size_t wrote; + + if (data->state.cancelled) { + /* We just suck everything into a black hole */ + return CURLE_OK; + } + + if(0 == len) + len = strlen(ptr); + + if(type & CLIENTWRITE_BODY) { + if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') { +#ifdef CURL_DOES_CONVERSIONS + /* convert from the network encoding */ + size_t rc; + rc = Curl_convert_from_network(data, ptr, len); + /* Curl_convert_from_network calls failf if unsuccessful */ + if(rc != CURLE_OK) + return rc; +#endif /* CURL_DOES_CONVERSIONS */ + +#ifdef CURL_DO_LINEEND_CONV + /* convert end-of-line markers */ + len = convert_lineends(data, ptr, len); +#endif /* CURL_DO_LINEEND_CONV */ + } + /* If the previous block of data ended with CR and this block of data is + just a NL, then the length might be zero */ + if (len) { + wrote = data->set.fwrite(ptr, 1, len, data->set.out); + } + else { + wrote = len; + } + + if(wrote != len) { + failf (data, "Failed writing body"); + return CURLE_WRITE_ERROR; + } + } + + if((type & CLIENTWRITE_HEADER) && + (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). + */ + curl_write_callback writeit= + data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite; + + /* Note: The header is in the host encoding + regardless of the ftp transfer mode (ASCII/Image) */ + + wrote = writeit(ptr, 1, len, data->set.writeheader); + if(wrote != len) { + failf (data, "Failed writing header"); + return CURLE_WRITE_ERROR; + } + } + + return CURLE_OK; +} + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * Internal read-from-socket function. This is meant to deal with plain + * sockets, SSL sockets and kerberos sockets. + * + * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return + * a regular CURLcode value. + */ +int Curl_read(struct connectdata *conn, /* connection data */ + 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 */ +{ + ssize_t nread; + size_t bytesfromsocket = 0; + char *buffertofill = NULL; + bool pipelining = (bool)(conn->data->multi && + Curl_multi_canPipeline(conn->data->multi)); + + /* 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 */ + + /* If session can pipeline, check connection buffer */ + if(pipelining) { + size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested); + + /* Copy from our master buffer first if we have some unread data there*/ + if (bytestocopy > 0) { + memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy); + conn->read_pos += bytestocopy; + conn->bits.stream_was_rewound = FALSE; + + *n = (ssize_t)bytestocopy; + return CURLE_OK; + } + /* If we come here, it means that there is no data to read from the buffer, + * so we read from the socket */ + bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer)); + buffertofill = conn->master_buffer; + } + else { + bytesfromsocket = MIN((long)sizerequested, conn->data->set.buffer_size ? + conn->data->set.buffer_size : BUFSIZE); + buffertofill = buf; + } + + if(conn->ssl[num].use) { + nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket); + + if(nread == -1) { + return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */ + } + } +#ifdef USE_LIBSSH2 + else if (conn->protocol & PROT_SCP) { + nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket); + /* TODO: return CURLE_OK also for nread <= 0 + read failures and timeouts ? */ + } + else if (conn->protocol & PROT_SFTP) { + nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket); + } +#endif /* !USE_LIBSSH2 */ + else { + if(conn->sec_complete) + nread = Curl_sec_read(conn, sockfd, buffertofill, + bytesfromsocket); + else + nread = sread(sockfd, buffertofill, bytesfromsocket); + + if(-1 == nread) { + int err = Curl_sockerrno(); +#ifdef USE_WINSOCK + if(WSAEWOULDBLOCK == err) +#else + if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)) +#endif + return -1; + } + } + + if (nread >= 0) { + if(pipelining) { + memcpy(buf, conn->master_buffer, nread); + conn->buf_len = nread; + conn->read_pos = nread; + } + + *n += nread; + } + + return CURLE_OK; +} + +/* return 0 on success */ +static int showit(struct SessionHandle *data, curl_infotype type, + char *ptr, size_t size) +{ + static const char * const s_infotype[CURLINFO_END] = { + "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; + +#ifdef CURL_DOES_CONVERSIONS + char buf[BUFSIZE+1]; + size_t conv_size = 0; + + switch(type) { + case CURLINFO_HEADER_OUT: + /* assume output headers are ASCII */ + /* copy the data into my buffer so the original is unchanged */ + if (size > BUFSIZE) { + size = BUFSIZE; /* truncate if necessary */ + buf[BUFSIZE] = '\0'; + } + conv_size = size; + memcpy(buf, ptr, size); + /* Special processing is needed for this block if it + * contains both headers and data (separated by CRLFCRLF). + * We want to convert just the headers, leaving the data as-is. + */ + if(size > 4) { + size_t i; + for(i = 0; i < size-4; i++) { + if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) { + /* convert everthing through this CRLFCRLF but no further */ + conv_size = i + 4; + break; + } + } + } + + Curl_convert_from_network(data, buf, conv_size); + /* Curl_convert_from_network calls failf if unsuccessful */ + /* we might as well continue even if it fails... */ + ptr = buf; /* switch pointer to use my buffer instead */ + break; + default: + /* leave everything else as-is */ + break; + } +#endif /* CURL_DOES_CONVERSIONS */ + + if(data->set.fdebug) + return (*data->set.fdebug)(data, type, ptr, size, + data->set.debugdata); + + switch(type) { + case CURLINFO_TEXT: + case CURLINFO_HEADER_OUT: + case CURLINFO_HEADER_IN: + fwrite(s_infotype[type], 2, 1, data->set.err); + fwrite(ptr, size, 1, data->set.err); +#ifdef CURL_DOES_CONVERSIONS + if(size != conv_size) { + /* we had untranslated data so we need an explicit newline */ + fwrite("\n", 1, 1, data->set.err); + } +#endif + break; + default: /* nada */ + break; + } + return 0; +} + +int Curl_debug(struct SessionHandle *data, curl_infotype type, + char *ptr, size_t size, + struct connectdata *conn) +{ + int rc; + if(data->set.printhost && conn && conn->host.dispname) { + char buffer[160]; + const char *t=NULL; + const char *w="Data"; + switch (type) { + case CURLINFO_HEADER_IN: + w = "Header"; + case CURLINFO_DATA_IN: + t = "from"; + break; + case CURLINFO_HEADER_OUT: + w = "Header"; + case CURLINFO_DATA_OUT: + t = "to"; + break; + default: + break; + } + + if(t) { + snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t, + conn->host.dispname); + rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer)); + if(rc) + return rc; + } + } + rc = showit(data, type, ptr, size); + return rc; +} diff --git a/Utilities/cmcurl/lib/sendf.h b/Utilities/cmcurl/lib/sendf.h new file mode 100644 index 0000000..7877df8 --- /dev/null +++ b/Utilities/cmcurl/lib/sendf.h @@ -0,0 +1,72 @@ +#ifndef __SENDF_H +#define __SENDF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, + const char *fmt, ...); +void Curl_infof(struct SessionHandle *, const char *fmt, ...); +void Curl_failf(struct SessionHandle *, const char *fmt, ...); + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) +#if defined(__GNUC__) +/* This style of variable argument macros is a gcc extension */ +#define infof(x...) /*ignore*/ +#else +/* C99 compilers could use this if we could detect them */ +/*#define infof(...) */ +/* Cast the args to void to make them a noop, side effects notwithstanding */ +#define infof (void) +#endif +#else +#define infof Curl_infof +#endif +#define failf Curl_failf + +#define CLIENTWRITE_BODY 1 +#define CLIENTWRITE_HEADER 2 +#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) + +CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, + size_t len); + +void Curl_read_rewind(struct connectdata *conn, + size_t extraBytesRead); + +/* internal read-function, does plain socket, SSL and krb4 */ +int Curl_read(struct connectdata *conn, curl_socket_t sockfd, + char *buf, size_t buffersize, + ssize_t *n); +/* internal write-function, does plain socket, SSL and krb4 */ +CURLcode Curl_write(struct connectdata *conn, + curl_socket_t sockfd, + void *mem, size_t len, + ssize_t *written); + +/* the function used to output verbose information */ +int Curl_debug(struct SessionHandle *handle, curl_infotype type, + char *data, size_t size, + struct connectdata *conn); + + +#endif diff --git a/Utilities/cmcurl/lib/setup.h b/Utilities/cmcurl/lib/setup.h new file mode 100644 index 0000000..5ae881f --- /dev/null +++ b/Utilities/cmcurl/lib/setup.h @@ -0,0 +1,390 @@ +#ifndef __LIB_CURL_SETUP_H +#define __LIB_CURL_SETUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifdef HTTP_ONLY +#define CURL_DISABLE_TFTP +#define CURL_DISABLE_FTP +#define CURL_DISABLE_LDAP +#define CURL_DISABLE_TELNET +#define CURL_DISABLE_DICT +#define CURL_DISABLE_FILE +#endif /* HTTP_ONLY */ + +#if !defined(WIN32) && defined(__WIN32__) +/* Borland fix */ +#define WIN32 +#endif + +#if !defined(WIN32) && defined(_WIN32) +/* VS2005 on x64 fix */ +#define WIN32 +#endif + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wcast-align" +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else + +/* +#ifdef _WIN32_WCE +#include "config-win32ce.h" +#else +#ifdef WIN32 +#include "config-win32.h" +#endif +#endif +*/ + +#ifdef macintosh +#include "config-mac.h" +#endif + +#ifdef AMIGA +#include "amigaos.h" +#endif + +#ifdef TPF +#include "config-tpf.h" /* hand-modified TPF config.h */ +/* change which select is used for libcurl */ +#define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e) +#endif + +#endif /* HAVE_CONFIG_H */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independant block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#if !defined(__cplusplus) && !defined(__BEOS__) && !defined(__ECOS) && !defined(typedef_bool) +typedef unsigned char bool; +#define typedef_bool +#endif + +#ifdef HAVE_LONGLONG +#define LONG_LONG long long +#define ENABLE_64BIT +#else +#ifdef _MSC_VER +#define LONG_LONG __int64 +#define ENABLE_64BIT +#endif /* _MSC_VER */ +#endif /* HAVE_LONGLONG */ + +#ifndef SIZEOF_CURL_OFF_T +/* If we don't know the size here, we assume a conservative size: 4. When + building libcurl, the actual size of this variable should be define in the + config*.h file. */ +#define SIZEOF_CURL_OFF_T 4 +#endif + +/* We set up our internal preferred (CURL_)FORMAT_OFF_T here */ +#if SIZEOF_CURL_OFF_T > 4 +#define FORMAT_OFF_T "lld" +#else +#define FORMAT_OFF_T "ld" +#endif /* SIZEOF_CURL_OFF_T */ + +#ifndef _REENTRANT +/* Solaris needs _REENTRANT set for a few function prototypes and things to + appear in the #include files. We need to #define it before all #include + files. Unixware needs it to build proper reentrant code. Others may also + need it. */ +#define _REENTRANT +#endif + +#include +#ifdef HAVE_ASSERT_H +#include +#endif +#include + +#ifdef __TANDEM /* for nsr-tandem-nsk systems */ +#include +#endif + +#ifndef STDC_HEADERS /* no standard C headers! */ +#include +#endif + +/* + * PellesC cludge section (yikes); + * - It has 'ssize_t', but it is in . The way the headers + * on Win32 are included, forces me to include this header here. + * - sys_nerr, EINTR is missing in v4.0 or older. + */ +#ifdef __POCC__ + #include + #include + #if (__POCC__ <= 400) + #define sys_nerr EILSEQ /* for strerror.c */ + #define EINTR -1 /* for select.c */ + #endif +#endif + +/* + * Salford-C cludge section (mostly borrowed from wxWidgets). + */ +#ifdef __SALFORDC__ + #pragma suppress 353 /* Possible nested comments */ + #pragma suppress 593 /* Define not used */ + #pragma suppress 61 /* enum has no name */ + #pragma suppress 106 /* unnamed, unused parameter */ + #include +#endif + +#if defined(CURLDEBUG) && defined(HAVE_ASSERT_H) +#define curlassert(x) assert(x) +#else +/* does nothing without CURLDEBUG defined */ +#define curlassert(x) +#endif + + +/* To make large file support transparent even on Windows */ +#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4) +#include /* must come first before we redefine stat() */ +#include +#define lseek(x,y,z) _lseeki64(x, y, z) +#define struct_stat struct _stati64 +#define stat(file,st) _stati64(file,st) +#define fstat(fd,st) _fstati64(fd,st) +#else +#define struct_stat struct stat +#endif /* Win32 with large file support */ + + +/* Below we define some functions. They should + 1. close a socket + + 4. set the SIGALRM signal timeout + 5. set dir/file naming defines + */ + +#ifdef WIN32 + +#if !defined(__CYGWIN__) +#define sclose(x) closesocket(x) + +#undef HAVE_ALARM +#else + /* gcc-for-win is still good :) */ +#define sclose(x) close(x) +#define HAVE_ALARM +#endif /* !GNU or mingw */ + +#define DIR_CHAR "\\" +#define DOT_CHAR "_" + +#else /* WIN32 */ + +#ifdef MSDOS /* Watt-32 */ +#include +#define sclose(x) close_s(x) +#define select(n,r,w,x,t) select_s(n,r,w,x,t) +#define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) +#define IOCTL_3_ARGS +#include +#ifdef word +#undef word +#endif + +#else /* MSDOS */ + +#ifdef __VMS +#define IOCTL_3_ARGS 1 +#endif + +#ifdef __BEOS__ +#define sclose(x) closesocket(x) +#else /* __BEOS__ */ +#define sclose(x) close(x) +#endif /* __BEOS__ */ + +#define HAVE_ALARM + +#endif /* MSDOS */ + +#ifdef _AMIGASF +#undef HAVE_ALARM +#undef sclose +#define sclose(x) CloseSocket(x) +#endif + +#define DIR_CHAR "/" +#ifndef DOT_CHAR +#define DOT_CHAR "." +#endif + +#ifdef MSDOS +#undef DOT_CHAR +#define DOT_CHAR "_" +#endif + +#ifndef fileno /* sunos 4 have this as a macro! */ +int fileno( FILE *stream); +#endif + +#endif /* WIN32 */ + +#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \ + !defined(__LCC__) /* lcc-win32 doesn't have _beginthreadex() */ +#ifdef ENABLE_IPV6 +#define USE_THREADING_GETADDRINFO +#else +#define USE_THREADING_GETHOSTBYNAME /* Cygwin uses alarm() function */ +#endif +#endif + +/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where + _beginthreadex() is not available */ +#if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES) +#undef USE_THREADING_GETADDRINFO +#undef USE_THREADING_GETHOSTBYNAME +#define CURL_NO__BEGINTHREADEX +#endif + +/* + * msvc 6.0 does not have struct sockaddr_storage and + * does not define IPPROTO_ESP in winsock2.h. But both + * are available if PSDK is properly installed. + */ + +#ifdef _MSC_VER +#if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP)) +#undef HAVE_STRUCT_SOCKADDR_STORAGE +#endif +#endif + +#ifdef mpeix +#define IOCTL_3_ARGS +#endif + +#ifdef NETWARE +#undef HAVE_ALARM +#endif + +#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H) +/* The lib was present and the tld.h header (which is missing in libidn 0.3.X + but we only work with libidn 0.4.1 or later) */ +#define USE_LIBIDN +#endif + +#ifndef SIZEOF_TIME_T +/* assume default size of time_t to be 32 bit */ +#define SIZEOF_TIME_T 4 +#endif + +#define LIBIDN_REQUIRED_VERSION "0.4.1" + +#ifdef __UCLIBC__ +#define HAVE_INET_NTOA_R_2_ARGS 1 +#endif + +#if defined(USE_GNUTLS) || defined(USE_SSLEAY) +#define USE_SSL /* Either OpenSSL || GnuTLS */ +#endif + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM) +#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) +#define USE_NTLM +#endif +#endif + +#ifdef CURLDEBUG +#define DEBUGF(x) x +#else +#define DEBUGF(x) +#endif + +/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */ +#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE) +#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* __LIB_CURL_SETUP_H */ diff --git a/Utilities/cmcurl/lib/setup_once.h b/Utilities/cmcurl/lib/setup_once.h new file mode 100644 index 0000000..ee68641 --- /dev/null +++ b/Utilities/cmcurl/lib/setup_once.h @@ -0,0 +1,153 @@ +#ifndef __SETUP_ONCE_H +#define __SETUP_ONCE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + + +/******************************************************************** + * NOTICE * + * ======== * + * * + * Content of header files lib/setup_once.h and ares/setup_once.h * + * must be kept in sync. Modify the other one if you change this. * + * * + ********************************************************************/ + + +/* + * If we have the MSG_NOSIGNAL define, make sure we use + * it as the fourth argument of function send() + */ + +#ifdef HAVE_MSG_NOSIGNAL +#define SEND_4TH_ARG MSG_NOSIGNAL +#else +#define SEND_4TH_ARG 0 +#endif + + +/* + * The definitions for the return type and arguments types + * of functions recv() and send() belong and come from the + * configuration file. Do not define them in any other place. + * + * 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 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 + * be defined. + * + * 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 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 + * SEND_TYPE_RETV must also be defined. + */ + +#ifdef HAVE_RECV +#if !defined(RECV_TYPE_ARG1) || \ + !defined(RECV_TYPE_ARG2) || \ + !defined(RECV_TYPE_ARG3) || \ + !defined(RECV_TYPE_ARG4) || \ + !defined(RECV_TYPE_RETV) + /* */ + Error Missing_definition_of_return_and_arguments_types_of_recv + /* */ +#else +#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ + (RECV_TYPE_ARG2)(y), \ + (RECV_TYPE_ARG3)(z), \ + (RECV_TYPE_ARG4)(0)) +#endif +#else /* HAVE_RECV */ +#ifndef sread + /* */ + Error Missing_definition_of_macro_sread + /* */ +#endif +#endif /* HAVE_RECV */ + +#ifdef HAVE_SEND +#if !defined(SEND_TYPE_ARG1) || \ + !defined(SEND_QUAL_ARG2) || \ + !defined(SEND_TYPE_ARG2) || \ + !defined(SEND_TYPE_ARG3) || \ + !defined(SEND_TYPE_ARG4) || \ + !defined(SEND_TYPE_RETV) + /* */ + Error Missing_definition_of_return_and_arguments_types_of_send + /* */ +#else +#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ + (SEND_TYPE_ARG2)(y), \ + (SEND_TYPE_ARG3)(z), \ + (SEND_TYPE_ARG4)(SEND_4TH_ARG)) +#endif +#else /* HAVE_SEND */ +#ifndef swrite + /* */ + Error Missing_definition_of_macro_swrite + /* */ +#endif +#endif /* HAVE_SEND */ + + +/* + * Uppercase macro versions of ANSI/ISO is*() functions/macros which + * avoid negative number inputs with argument byte codes > 127. + */ + +#define ISSPACE(x) (isspace((int) ((unsigned char)x))) +#define ISDIGIT(x) (isdigit((int) ((unsigned char)x))) +#define ISALNUM(x) (isalnum((int) ((unsigned char)x))) +#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) +#define ISGRAPH(x) (isgraph((int) ((unsigned char)x))) +#define ISALPHA(x) (isalpha((int) ((unsigned char)x))) +#define ISPRINT(x) (isprint((int) ((unsigned char)x))) + + +/* + * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. + */ + +#ifndef HAVE_SIG_ATOMIC_T +typedef int sig_atomic_t; +#define HAVE_SIG_ATOMIC_T +#endif + + +/* + * Default return type for signal handlers. + */ + +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif + + +#endif /* __SETUP_ONCE_H */ + diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c new file mode 100644 index 0000000..de13b60 --- /dev/null +++ b/Utilities/cmcurl/lib/share.c @@ -0,0 +1,219 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include +#include +#include +#include +#include "urldata.h" +#include "share.h" +#include "memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +CURLSH * +curl_share_init(void) +{ + struct Curl_share *share = + (struct Curl_share *)malloc(sizeof(struct Curl_share)); + if (share) { + memset (share, 0, sizeof(struct Curl_share)); + share->specifier |= (1<dirty) + /* don't allow setting options while one or more handles are already + using this share */ + return CURLSHE_IN_USE; + + va_start(param, option); + + switch(option) { + case CURLSHOPT_SHARE: + /* this is a type this share will share */ + type = va_arg(param, int); + share->specifier |= (1<hostcache) { + share->hostcache = Curl_mk_dnscache(); + if(!share->hostcache) + return CURLSHE_NOMEM; + } + break; + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + case CURL_LOCK_DATA_COOKIE: + if (!share->cookies) { + share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE ); + if(!share->cookies) + return CURLSHE_NOMEM; + } + break; +#endif /* CURL_DISABLE_HTTP */ + + case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */ + case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ + + default: + return CURLSHE_BAD_OPTION; + } + break; + + case CURLSHOPT_UNSHARE: + /* this is a type this share will no longer share */ + type = va_arg(param, int); + share->specifier &= ~(1<hostcache) { + Curl_hash_destroy(share->hostcache); + share->hostcache = NULL; + } + break; + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + case CURL_LOCK_DATA_COOKIE: + if (share->cookies) { + Curl_cookie_cleanup(share->cookies); + share->cookies = NULL; + } + break; +#endif /* CURL_DISABLE_HTTP */ + + case CURL_LOCK_DATA_SSL_SESSION: + break; + + case CURL_LOCK_DATA_CONNECT: + break; + + default: + return CURLSHE_BAD_OPTION; + } + break; + + case CURLSHOPT_LOCKFUNC: + lockfunc = va_arg(param, curl_lock_function); + share->lockfunc = lockfunc; + break; + + case CURLSHOPT_UNLOCKFUNC: + unlockfunc = va_arg(param, curl_unlock_function); + share->unlockfunc = unlockfunc; + break; + + case CURLSHOPT_USERDATA: + ptr = va_arg(param, void *); + share->clientdata = ptr; + break; + + default: + return CURLSHE_BAD_OPTION; + } + + return CURLSHE_OK; +} + +CURLSHcode +curl_share_cleanup(CURLSH *sh) +{ + struct Curl_share *share = (struct Curl_share *)sh; + + if (share == NULL) + return CURLSHE_INVALID; + + if(share->lockfunc) + share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE, + share->clientdata); + + if (share->dirty) { + if(share->unlockfunc) + share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); + return CURLSHE_IN_USE; + } + + if(share->hostcache) + Curl_hash_destroy(share->hostcache); + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(share->cookies) + Curl_cookie_cleanup(share->cookies); +#endif /* CURL_DISABLE_HTTP */ + + if(share->unlockfunc) + share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); + free(share); + + return CURLSHE_OK; +} + + +CURLSHcode +Curl_share_lock(struct SessionHandle *data, curl_lock_data type, + curl_lock_access accesstype) +{ + struct Curl_share *share = data->share; + + if (share == NULL) + return CURLSHE_INVALID; + + if(share->specifier & (1<lockfunc) /* only call this if set! */ + share->lockfunc(data, type, accesstype, share->clientdata); + } + /* else if we don't share this, pretend successful lock */ + + return CURLSHE_OK; +} + +CURLSHcode +Curl_share_unlock(struct SessionHandle *data, curl_lock_data type) +{ + struct Curl_share *share = data->share; + + if (share == NULL) + return CURLSHE_INVALID; + + if(share->specifier & (1<unlockfunc) /* only call this if set! */ + share->unlockfunc (data, type, share->clientdata); + } + + return CURLSHE_OK; +} diff --git a/Utilities/cmcurl/lib/share.h b/Utilities/cmcurl/lib/share.h new file mode 100644 index 0000000..5cfe8c7 --- /dev/null +++ b/Utilities/cmcurl/lib/share.h @@ -0,0 +1,56 @@ +#ifndef __CURL_SHARE_H +#define __CURL_SHARE_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include +#include "cookie.h" + +/* SalfordC says "A structure member may not be volatile". Hence: + */ +#ifdef __SALFORDC__ +#define CURL_VOLATILE +#else +#define CURL_VOLATILE volatile +#endif + +/* this struct is libcurl-private, don't export details */ +struct Curl_share { + unsigned int specifier; + CURL_VOLATILE unsigned int dirty; + + curl_lock_function lockfunc; + curl_unlock_function unlockfunc; + void *clientdata; + + struct curl_hash *hostcache; + struct CookieInfo *cookies; +}; + +CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, + curl_lock_access); +CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data); + +#endif /* __CURL_SHARE_H */ diff --git a/Utilities/cmcurl/lib/sockaddr.h b/Utilities/cmcurl/lib/sockaddr.h new file mode 100644 index 0000000..78dad4d --- /dev/null +++ b/Utilities/cmcurl/lib/sockaddr.h @@ -0,0 +1,38 @@ +#ifndef __SOCKADDR_H +#define __SOCKADDR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE +struct Curl_sockaddr_storage { + struct sockaddr_storage buffer; +}; +#else +struct Curl_sockaddr_storage { + char buffer[256]; /* this should be big enough to fit a lot */ +}; +#endif + +#endif /* __SOCKADDR_H */ diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c new file mode 100644 index 0000000..e0e947b --- /dev/null +++ b/Utilities/cmcurl/lib/socks.c @@ -0,0 +1,592 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef NEED_MALLOC_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "strequal.h" +#include "select.h" +#include "connect.h" +#include "timeval.h" +#include "socks.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Helper read-from-socket functions. Does the same as Curl_read() but it + * blocks until all bytes amount of buffersize will be read. No more, no less. + * + * This is STUPID BLOCKING behaviour which we frown upon, but right now this + * is what we have... + */ +static int blockread_all(struct connectdata *conn, /* connection data */ + curl_socket_t sockfd, /* read from this socket */ + char *buf, /* store read data here */ + ssize_t buffersize, /* max amount to read */ + ssize_t *n, /* amount bytes read */ + long conn_timeout) /* timeout for data wait + relative to + conn->created */ +{ + ssize_t nread; + ssize_t allread = 0; + int result; + struct timeval tvnow; + long conntime; + *n = 0; + do { + tvnow = Curl_tvnow(); + /* calculating how long connection is establishing */ + conntime = Curl_tvdiff(tvnow, conn->created); + if(conntime > conn_timeout) { + /* we already got the timeout */ + result = ~CURLE_OK; + break; + } + if(Curl_select(sockfd, CURL_SOCKET_BAD, + (int)(conn_timeout - conntime)) <= 0) { + result = ~CURLE_OK; + break; + } + result = Curl_read(conn, sockfd, buf, buffersize, &nread); + if(result) + break; + + if(buffersize == nread) { + allread += nread; + *n = allread; + result = CURLE_OK; + break; + } + buffersize -= nread; + buf += nread; + allread += nread; + } while(1); + return result; +} + +/* +* This function logs in to a SOCKS4 proxy and sends the specifics to the final +* destination server. +* +* Reference : +* http://socks.permeo.com/protocol/socks4.protocol +* +* Note : +* Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" +* Nonsupport "Identification Protocol (RFC1413)" +*/ +CURLcode Curl_SOCKS4(const char *proxy_name, + struct connectdata *conn) +{ + unsigned char socksreq[262]; /* room for SOCKS4 request incl. user id */ + int result; + CURLcode code; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + long timeout; + struct SessionHandle *data = conn->data; + + /* get timeout */ + if(data->set.timeout && data->set.connecttimeout) { + if (data->set.timeout < data->set.connecttimeout) + timeout = data->set.timeout*1000; + else + timeout = data->set.connecttimeout*1000; + } + else if(data->set.timeout) + timeout = data->set.timeout*1000; + else if(data->set.connecttimeout) + timeout = data->set.connecttimeout*1000; + else + timeout = DEFAULT_CONNECT_TIMEOUT; + + Curl_nonblock(sock, FALSE); + + /* + * Compose socks4 request + * + * Request format + * + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * | VN | CD | DSTPORT | DSTIP | USERID |NULL| + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * # of bytes: 1 1 2 4 variable 1 + */ + + socksreq[0] = 4; /* version (SOCKS4) */ + socksreq[1] = 1; /* connect */ + *((unsigned short*)&socksreq[2]) = htons(conn->remote_port); + + /* DNS resolve */ + { + struct Curl_dns_entry *dns; + Curl_addrinfo *hp=NULL; + int rc; + + rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLE_COULDNT_RESOLVE_PROXY; + + if(rc == CURLRESOLV_PENDING) + /* this requires that we're in "wait for resolve" state */ + rc = Curl_wait_for_resolv(conn, &dns); + + /* + * 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) + hp=dns->addr; + if (hp) { + char buf[64]; + unsigned short ip[4]; + Curl_printable_address(hp, buf, sizeof(buf)); + + if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3])) { + /* Set DSTIP */ + socksreq[4] = (unsigned char)ip[0]; + socksreq[5] = (unsigned char)ip[1]; + socksreq[6] = (unsigned char)ip[2]; + socksreq[7] = (unsigned char)ip[3]; + } + else + hp = NULL; /* fail! */ + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + + } + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", + conn->host.name); + return CURLE_COULDNT_RESOLVE_HOST; + } + } + + /* + * This is currently not supporting "Identification Protocol (RFC1413)". + */ + socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ + if(proxy_name) { + size_t plen = strlen(proxy_name); + if(plen >= sizeof(socksreq) - 8) { + failf(data, "Too long SOCKS proxy name, can't use!\n"); + return CURLE_COULDNT_CONNECT; + } + /* copy the proxy name WITH trailing zero */ + memcpy(socksreq + 8, proxy_name, plen+1); + } + + /* + * Make connection + */ + { + ssize_t actualread; + ssize_t written; + int packetsize = 9 + + (int)strlen((char*)socksreq + 8); /* size including NUL */ + + /* Send request */ + code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); + if ((code != CURLE_OK) || (written != packetsize)) { + failf(data, "Failed to send SOCKS4 connect request."); + return CURLE_COULDNT_CONNECT; + } + + packetsize = 8; /* receive data size */ + + /* Receive response */ + result = blockread_all(conn, sock, (char *)socksreq, packetsize, + &actualread, timeout); + if ((result != CURLE_OK) || (actualread != packetsize)) { + failf(data, "Failed to receive SOCKS4 connect request ack."); + return CURLE_COULDNT_CONNECT; + } + + /* + * Response format + * + * +----+----+----+----+----+----+----+----+ + * | VN | CD | DSTPORT | DSTIP | + * +----+----+----+----+----+----+----+----+ + * # of bytes: 1 1 2 4 + * + * VN is the version of the reply code and should be 0. CD is the result + * code with one of the following values: + * + * 90: request granted + * 91: request rejected or failed + * 92: request rejected because SOCKS server cannot connect to + * identd on the client + * 93: request rejected because the client program and identd + * report different user-ids + */ + + /* wrong version ? */ + if (socksreq[0] != 0) { + failf(data, + "SOCKS4 reply has wrong version, version should be 4."); + return CURLE_COULDNT_CONNECT; + } + + /* Result */ + switch(socksreq[1]) + { + case 90: + infof(data, "SOCKS4 request granted.\n"); + break; + case 91: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected or failed.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), + socksreq[1]); + return CURLE_COULDNT_CONNECT; + case 92: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because SOCKS server cannot connect to " + "identd on the client.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), + socksreq[1]); + return CURLE_COULDNT_CONNECT; + case 93: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", request rejected because the client program and identd " + "report different user-ids.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), + socksreq[1]); + return CURLE_COULDNT_CONNECT; + default: + failf(data, + "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + ", Unknown.", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), + socksreq[1]); + return CURLE_COULDNT_CONNECT; + } + } + + Curl_nonblock(sock, TRUE); + + return CURLE_OK; /* Proxy was successful! */ +} + +/* + * This function logs in to a SOCKS5 proxy and sends the specifics to the final + * destination server. + */ +CURLcode Curl_SOCKS5(const char *proxy_name, + const char *proxy_password, + struct connectdata *conn) +{ + /* + According to the RFC1928, section "6. Replies". This is what a SOCK5 + replies: + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + Where: + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + */ + + unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ + ssize_t actualread; + ssize_t written; + int result; + CURLcode code; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + struct SessionHandle *data = conn->data; + long timeout; + + /* get timeout */ + if(data->set.timeout && data->set.connecttimeout) { + if (data->set.timeout < data->set.connecttimeout) + timeout = data->set.timeout*1000; + else + timeout = data->set.connecttimeout*1000; + } + else if(data->set.timeout) + timeout = data->set.timeout*1000; + else if(data->set.connecttimeout) + timeout = data->set.connecttimeout*1000; + else + timeout = DEFAULT_CONNECT_TIMEOUT; + + Curl_nonblock(sock, TRUE); + + /* wait until socket gets connected */ + result = Curl_select(CURL_SOCKET_BAD, sock, (int)timeout); + + if(-1 == result) { + failf(conn->data, "SOCKS5: no connection here"); + return CURLE_COULDNT_CONNECT; + } + else if(0 == result) { + failf(conn->data, "SOCKS5: connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + if(result & CSELECT_ERR) { + failf(conn->data, "SOCKS5: error occured during connection"); + return CURLE_COULDNT_CONNECT; + } + + socksreq[0] = 5; /* version */ + socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */ + socksreq[2] = 0; /* no authentication */ + socksreq[3] = 2; /* username/password */ + + Curl_nonblock(sock, FALSE); + + code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), + &written); + if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) { + failf(data, "Unable to send initial SOCKS5 request."); + return CURLE_COULDNT_CONNECT; + } + + Curl_nonblock(sock, TRUE); + + result = Curl_select(sock, CURL_SOCKET_BAD, (int)timeout); + + if(-1 == result) { + failf(conn->data, "SOCKS5 nothing to read"); + return CURLE_COULDNT_CONNECT; + } + else if(0 == result) { + failf(conn->data, "SOCKS5 read timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + if(result & CSELECT_ERR) { + failf(conn->data, "SOCKS5 read error occured"); + return CURLE_RECV_ERROR; + } + + Curl_nonblock(sock, FALSE); + + result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, timeout); + if ((result != CURLE_OK) || (actualread != 2)) { + failf(data, "Unable to receive initial SOCKS5 response."); + return CURLE_COULDNT_CONNECT; + } + + if (socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLE_COULDNT_CONNECT; + } + if (socksreq[1] == 0) { + /* Nothing to do, no authentication needed */ + ; + } + else if (socksreq[1] == 2) { + /* Needs user name and password */ + size_t userlen, pwlen; + int len; + if(proxy_name && proxy_password) { + userlen = strlen(proxy_name); + pwlen = proxy_password?strlen(proxy_password):0; + } + else { + userlen = 0; + pwlen = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (char) userlen; + memcpy(socksreq + len, proxy_name, (int) userlen); + len += userlen; + socksreq[len++] = (char) pwlen; + memcpy(socksreq + len, proxy_password, (int) pwlen); + len += pwlen; + + code = Curl_write(conn, sock, (char *)socksreq, len, &written); + if ((code != CURLE_OK) || (len != written)) { + failf(data, "Failed to send SOCKS5 sub-negotiation request."); + return CURLE_COULDNT_CONNECT; + } + + result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, + timeout); + if ((result != CURLE_OK) || (actualread != 2)) { + failf(data, "Unable to receive SOCKS5 sub-negotiation response."); + return CURLE_COULDNT_CONNECT; + } + + /* ignore the first (VER) byte */ + if (socksreq[1] != 0) { /* status */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return CURLE_COULDNT_CONNECT; + } + + /* Everything is good so far, user was authenticated! */ + } + else { + /* error */ + if (socksreq[1] == 1) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLE_COULDNT_CONNECT; + } + else if (socksreq[1] == 255) { + if (!proxy_name || !*proxy_name) { + failf(data, + "No authentication method was acceptable. (It is quite likely" + " that the SOCKS5 server wanted a username/password, since none" + " was supplied to the server on this connection.)"); + } + else { + failf(data, "No authentication method was acceptable."); + } + return CURLE_COULDNT_CONNECT; + } + else { + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLE_COULDNT_CONNECT; + } + } + + /* Authentication is complete, now specify destination to the proxy */ + socksreq[0] = 5; /* version (SOCKS5) */ + socksreq[1] = 1; /* connect */ + socksreq[2] = 0; /* must be zero */ + socksreq[3] = 1; /* IPv4 = 1 */ + + { + struct Curl_dns_entry *dns; + Curl_addrinfo *hp=NULL; + int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLE_COULDNT_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) + /* this requires that we're in "wait for resolve" state */ + rc = Curl_wait_for_resolv(conn, &dns); + + /* + * 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) + hp=dns->addr; + if (hp) { + char buf[64]; + unsigned short ip[4]; + Curl_printable_address(hp, buf, sizeof(buf)); + + if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3])) { + socksreq[4] = (unsigned char)ip[0]; + socksreq[5] = (unsigned char)ip[1]; + socksreq[6] = (unsigned char)ip[2]; + socksreq[7] = (unsigned char)ip[3]; + } + else + hp = NULL; /* fail! */ + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + } + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + conn->host.name); + return CURLE_COULDNT_RESOLVE_HOST; + } + } + + *((unsigned short*)&socksreq[8]) = htons(conn->remote_port); + + { + const int packetsize = 10; + + code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); + if ((code != CURLE_OK) || (written != packetsize)) { + failf(data, "Failed to send SOCKS5 connect request."); + return CURLE_COULDNT_CONNECT; + } + + result = blockread_all(conn, sock, (char *)socksreq, packetsize, + &actualread, timeout); + if ((result != CURLE_OK) || (actualread != packetsize)) { + failf(data, "Failed to receive SOCKS5 connect request ack."); + return CURLE_COULDNT_CONNECT; + } + + if (socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLE_COULDNT_CONNECT; + } + if (socksreq[1] != 0) { /* Anything besides 0 is an error */ + failf(data, + "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), + socksreq[1]); + return CURLE_COULDNT_CONNECT; + } + } + + Curl_nonblock(sock, TRUE); + return CURLE_OK; /* Proxy was successful! */ +} diff --git a/Utilities/cmcurl/lib/socks.h b/Utilities/cmcurl/lib/socks.h new file mode 100644 index 0000000..0da9879 --- /dev/null +++ b/Utilities/cmcurl/lib/socks.h @@ -0,0 +1,41 @@ +#ifndef __SOCKS_H +#define __SOCKS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * This function logs in to a SOCKS4 proxy and sends the specifics to the + * final destination server. + */ +CURLcode Curl_SOCKS4(const char *proxy_name, + struct connectdata *conn); + +/* + * This function logs in to a SOCKS5 proxy and sends the specifics to the + * final destination server. + */ +CURLcode Curl_SOCKS5(const char *proxy_name, + const char *proxy_password, + struct connectdata *conn); + +#endif diff --git a/Utilities/cmcurl/lib/speedcheck.c b/Utilities/cmcurl/lib/speedcheck.c new file mode 100644 index 0000000..adda8a9 --- /dev/null +++ b/Utilities/cmcurl/lib/speedcheck.c @@ -0,0 +1,75 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#include +#include "urldata.h" +#include "sendf.h" +#include "multiif.h" +#include "speedcheck.h" + +void Curl_speedinit(struct SessionHandle *data) +{ + memset(&data->state.keeps_speed, 0, sizeof(struct timeval)); +} + +CURLcode Curl_speedcheck(struct SessionHandle *data, + struct timeval now) +{ + if((data->progress.current_speed >= 0) && + data->set.low_speed_time && + (Curl_tvlong(data->state.keeps_speed) != 0) && + (data->progress.current_speed < data->set.low_speed_limit)) { + long howlong = Curl_tvdiff(now, data->state.keeps_speed); + + /* We are now below the "low speed limit". If we are below it + for "low speed time" seconds we consider that enough reason + to abort the download. */ + + if( (howlong/1000) > data->set.low_speed_time) { + /* we have been this slow for long enough, now die */ + failf(data, + "Operation too slow. " + "Less than %d bytes/sec transfered the last %d seconds", + data->set.low_speed_limit, + data->set.low_speed_time); + return CURLE_OPERATION_TIMEOUTED; + } + Curl_expire(data, howlong); + } + else { + /* we keep up the required speed all right */ + data->state.keeps_speed = now; + + if(data->set.low_speed_limit) + /* if there is a low speed limit enabled, we set the expire timer to + make this connection's speed get checked again no later than when + this time is up */ + Curl_expire(data, data->set.low_speed_time*1000); + } + return CURLE_OK; +} diff --git a/Utilities/cmcurl/lib/speedcheck.h b/Utilities/cmcurl/lib/speedcheck.h new file mode 100644 index 0000000..62475f6 --- /dev/null +++ b/Utilities/cmcurl/lib/speedcheck.h @@ -0,0 +1,34 @@ +#ifndef __SPEEDCHECK_H +#define __SPEEDCHECK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include "timeval.h" + +void Curl_speedinit(struct SessionHandle *data); +CURLcode Curl_speedcheck(struct SessionHandle *data, + struct timeval now); + +#endif diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c new file mode 100644 index 0000000..9fb66c7 --- /dev/null +++ b/Utilities/cmcurl/lib/splay.c @@ -0,0 +1,425 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1997 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include +#include + +#include "splay.h" + +#define compare(i,j) ((i)-(j)) + +/* Set this to a key value that will *NEVER* appear otherwise */ +#define KEY_NOTUSED -1 + +/* + * Splay using the key i (which may or may not be in the tree.) The starting + * root is t. + */ +struct Curl_tree *Curl_splay(int i, struct Curl_tree *t) +{ + struct Curl_tree N, *l, *r, *y; + int comp; + + if (t == NULL) + return t; + N.smaller = N.larger = NULL; + l = r = &N; + + for (;;) { + comp = compare(i, t->key); + if (comp < 0) { + if (t->smaller == NULL) + break; + if (compare(i, t->smaller->key) < 0) { + y = t->smaller; /* rotate smaller */ + t->smaller = y->larger; + y->larger = t; + t = y; + if (t->smaller == NULL) + break; + } + r->smaller = t; /* link smaller */ + r = t; + t = t->smaller; + } + else if (comp > 0) { + if (t->larger == NULL) + break; + if (compare(i, t->larger->key) > 0) { + y = t->larger; /* rotate larger */ + t->larger = y->smaller; + y->smaller = t; + t = y; + if (t->larger == NULL) + break; + } + l->larger = t; /* link larger */ + l = t; + t = t->larger; + } + else + break; + } + + l->larger = t->smaller; /* assemble */ + r->smaller = t->larger; + t->smaller = N.larger; + t->larger = N.smaller; + + return t; +} + +/* Insert key i into the tree t. Return a pointer to the resulting tree or + NULL if something went wrong. */ +struct Curl_tree *Curl_splayinsert(int i, + struct Curl_tree *t, + struct Curl_tree *node) +{ + if (node == NULL) + return t; + + if (t != NULL) { + t = Curl_splay(i,t); + if (compare(i, t->key)==0) { + /* There already exists a node in the tree with the very same key. Build + a linked list of nodes. We make the new 'node' struct the new master + node and make the previous node the first one in the 'same' list. */ + + node->same = t; + node->key = i; + node->smaller = t->smaller; + node->larger = t->larger; + + t->smaller = node; /* in the sub node for this same key, we use the + smaller pointer to point back to the master + node */ + + t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED + to quickly identify this node as a subnode */ + + return node; /* new root node */ + } + } + + if (t == NULL) { + node->smaller = node->larger = NULL; + } + else if (compare(i, t->key) < 0) { + node->smaller = t->smaller; + node->larger = t; + t->smaller = NULL; + + } + else { + node->larger = t->larger; + node->smaller = t; + t->larger = NULL; + } + node->key = i; + + node->same = NULL; /* no identical node (yet) */ + return node; +} + +#if 0 +/* Deletes 'i' from the tree if it's there (with an exact match). Returns a + pointer to the resulting tree. + + Function not used in libcurl. +*/ +struct Curl_tree *Curl_splayremove(int i, struct Curl_tree *t, + struct Curl_tree **removed) +{ + struct Curl_tree *x; + + *removed = NULL; /* default to no removed */ + + if (t==NULL) + return NULL; + + t = Curl_splay(i,t); + if (compare(i, t->key) == 0) { /* found it */ + + /* FIRST! Check if there is a list with identical sizes */ + if((x = t->same)) { + /* there is, pick one from the list */ + + /* 'x' is the new root node */ + + x->key = t->key; + x->larger = t->larger; + x->smaller = t->smaller; + + *removed = t; + return x; /* new root */ + } + + if (t->smaller == NULL) { + x = t->larger; + } + else { + x = Curl_splay(i, t->smaller); + x->larger = t->larger; + } + *removed = t; + + return x; + } + else + return t; /* It wasn't there */ +} +#endif + +/* Finds and deletes the best-fit node from the tree. Return a pointer to the + resulting tree. best-fit means the node with the given or lower number */ +struct Curl_tree *Curl_splaygetbest(int i, struct Curl_tree *t, + struct Curl_tree **removed) +{ + struct Curl_tree *x; + + if (!t) { + *removed = NULL; /* none removed since there was no root */ + return NULL; + } + + t = Curl_splay(i,t); + if(compare(i, t->key) < 0) { + /* too big node, try the smaller chain */ + if(t->smaller) + t=Curl_splay(t->smaller->key, t); + else { + /* fail */ + *removed = NULL; + return t; + } + } + + if (compare(i, t->key) >= 0) { /* found it */ + /* FIRST! Check if there is a list with identical sizes */ + x = t->same; + if(x) { + /* there is, pick one from the list */ + + /* 'x' is the new root node */ + + x->key = t->key; + x->larger = t->larger; + x->smaller = t->smaller; + + *removed = t; + return x; /* new root */ + } + + if (t->smaller == NULL) { + x = t->larger; + } + else { + x = Curl_splay(i, t->smaller); + x->larger = t->larger; + } + *removed = t; + + return x; + } + else { + *removed = NULL; /* no match */ + return t; /* It wasn't there */ + } +} + + +/* 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! TODO: document error codes. + When returning error, it does not touch the 'newroot' pointer. + + NOTE: when the last node of the tree is removed, there's no tree left so + 'newroot' will be made to point to NULL. +*/ +int Curl_splayremovebyaddr(struct Curl_tree *t, + struct Curl_tree *remove, + struct Curl_tree **newroot) +{ + struct Curl_tree *x; + + if (!t || !remove) + return 1; + + if(KEY_NOTUSED == remove->key) { + /* Key set to NOTUSED means it is a subnode within a 'same' linked list + and thus we can unlink it easily. The 'smaller' link of a subnode + links to the parent node. */ + if (remove->smaller == NULL) + return 3; + + remove->smaller->same = remove->same; + if(remove->same) + remove->same->smaller = remove->smaller; + + /* Ensures that double-remove gets caught. */ + remove->smaller = NULL; + + /* voila, we're done! */ + *newroot = t; /* return the same root */ + return 0; + } + + t = Curl_splay(remove->key, 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 + 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 + could return the same key but a different node. */ + if(t != remove) + return 2; + + /* 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->same; + if(x) { + /* 'x' is the new root node, we just make it use the root node's + smaller/larger links */ + + x->key = t->key; + x->larger = t->larger; + x->smaller = t->smaller; + } + else { + /* Remove the root node */ + if (t->smaller == NULL) + x = t->larger; + else { + x = Curl_splay(remove->key, t->smaller); + x->larger = t->larger; + } + } + + *newroot = x; /* store new root pointer */ + + return 0; +} + +#ifdef CURLDEBUG + +void Curl_splayprint(struct Curl_tree * t, int d, char output) +{ + struct Curl_tree *node; + int i; + int count; + if (t == NULL) + return; + + Curl_splayprint(t->larger, d+1, output); + for (i=0; ikey, i); + } + + for(count=0, node = t->same; node; node = node->same, count++) + ; + + if(output) { + if(count) + printf(" [%d more]\n", count); + else + printf("\n"); + } + + Curl_splayprint(t->smaller, d+1, output); +} +#endif + +#ifdef TEST_SPLAY + +/*#define TEST2 */ +#define MAX 50 +#define TEST2 + +/* A sample use of these functions. Start with the empty tree, insert some + stuff into it, and then delete it */ +int main(int argc, char **argv) +{ + struct Curl_tree *root, *t; + void *ptrs[MAX]; + int adds=0; + int rc; + + long sizes[]={ + 50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300, + 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, + 300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, + 200, 300, 220, 80, 90}; + int i; + root = NULL; /* the empty tree */ + + for (i = 0; i < MAX; i++) { + int key; + ptrs[i] = t = (struct Curl_tree *)malloc(sizeof(struct Curl_tree)); + +#ifdef TEST2 + key = sizes[i]; +#elif defined(TEST1) + key = (541*i)%1023; +#elif defined(TEST3) + key = 100; +#endif + + t->payload = (void *)key; /* for simplicity */ + if(!t) { + puts("out of memory!"); + return 0; + } + root = Curl_splayinsert(key, root, t); + } + +#if 0 + puts("Result:"); + Curl_splayprint(root, 0, 1); +#endif + +#if 1 + for (i = 0; i < MAX; i++) { + int rem = (i+7)%MAX; + struct Curl_tree *r; + printf("Tree look:\n"); + Curl_splayprint(root, 0, 1); + printf("remove pointer %d, payload %d\n", rem, + (int)((struct Curl_tree *)ptrs[rem])->payload); + rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root); + if(rc) + /* failed! */ + printf("remove %d failed!\n", rem); + } +#endif + + return 0; +} + +#endif /* TEST_SPLAY */ diff --git a/Utilities/cmcurl/lib/splay.h b/Utilities/cmcurl/lib/splay.h new file mode 100644 index 0000000..1674534 --- /dev/null +++ b/Utilities/cmcurl/lib/splay.h @@ -0,0 +1,54 @@ +#ifndef __SPLAY_H +#define __SPLAY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1997 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +struct Curl_tree { + struct Curl_tree *smaller; /* smaller node */ + struct Curl_tree *larger; /* larger node */ + struct Curl_tree *same; /* points to a node with identical key */ + int key; /* the "sort" key */ + void *payload; /* data the splay code doesn't care about */ +}; + +struct Curl_tree *Curl_splay(int i, struct Curl_tree *t); +struct Curl_tree *Curl_splayinsert(int key, struct Curl_tree *t, + struct Curl_tree *newnode); +#if 0 +struct Curl_tree *Curl_splayremove(int key, struct Curl_tree *t, + struct Curl_tree **removed); +#endif + +struct Curl_tree *Curl_splaygetbest(int key, struct Curl_tree *t, + struct Curl_tree **removed); +int Curl_splayremovebyaddr(struct Curl_tree *t, + struct Curl_tree *remove, + struct Curl_tree **newroot); + +#ifdef CURLDEBUG +void Curl_splayprint(struct Curl_tree * t, int d, char output); +#else +#define Curl_splayprint(x,y,z) +#endif + +#endif diff --git a/Utilities/cmcurl/lib/ssh.c b/Utilities/cmcurl/lib/ssh.c new file mode 100644 index 0000000..24cba1b --- /dev/null +++ b/Utilities/cmcurl/lib/ssh.c @@ -0,0 +1,979 @@ +/*************************************************************************** +* _ _ ____ _ +* Project ___| | | | _ \| | +* / __| | | | |_) | | +* | (__| |_| | _ <| |___ +* \___|\___/|_| \_\_____| +* +* Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. +* +* $Id$ +***************************************************************************/ + +/* #define CURL_LIBSSH2_DEBUG */ + +#include "setup.h" + +#ifdef USE_LIBSSH2 +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_TIME_H +#include +#endif + +#ifdef WIN32 + +#else /* probably some kind of unix */ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_UTSNAME_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef VMS +#include +#include +#endif +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "easyif.h" /* for Curl_convert_... prototypes */ + +#include "if2ip.h" +#include "hostip.h" +#include "progress.h" +#include "transfer.h" +#include "escape.h" +#include "http.h" /* for HTTP proxy tunnel stuff */ +#include "ssh.h" +#include "url.h" +#include "speedcheck.h" +#include "getinfo.h" + +#include "strtoofft.h" +#include "strequal.h" +#include "sslgen.h" +#include "connect.h" +#include "strerror.h" +#include "memory.h" +#include "inet_ntop.h" +#include "select.h" +#include "parsedate.h" /* for the week day and month names */ +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "multiif.h" + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) +#define DIRSEP '\\' +#else +#define DIRSEP '/' +#endif + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#ifdef CURLDEBUG +#include "memdebug.h" +#endif + +#ifndef LIBSSH2_SFTP_S_IRUSR +/* Here's a work-around for those of you who happend to run a libssh2 version + that is 0.14 or older. We should remove this kludge as soon as we can + require a more recent libssh2 release. */ +#ifndef S_IRGRP +#define S_IRGRP 0 +#endif + +#ifndef S_IROTH +#define S_IROTH 0 +#endif + +#define LIBSSH2_SFTP_S_IRUSR S_IRUSR +#define LIBSSH2_SFTP_S_IWUSR S_IWUSR +#define LIBSSH2_SFTP_S_IRGRP S_IRGRP +#define LIBSSH2_SFTP_S_IROTH S_IROTH +#define LIBSSH2_SFTP_S_IRUSR S_IRUSR +#define LIBSSH2_SFTP_S_IWUSR S_IWUSR +#define LIBSSH2_SFTP_S_IRGRP S_IRGRP +#define LIBSSH2_SFTP_S_IROTH S_IROTH +#define LIBSSH2_SFTP_S_IFMT S_IFMT +#define LIBSSH2_SFTP_S_IFDIR S_IFDIR +#define LIBSSH2_SFTP_S_IFLNK S_IFLNK +#define LIBSSH2_SFTP_S_IFSOCK S_IFSOCK +#define LIBSSH2_SFTP_S_IFCHR S_IFCHR +#define LIBSSH2_SFTP_S_IFBLK S_IFBLK +#define LIBSSH2_SFTP_S_IXUSR S_IXUSR +#define LIBSSH2_SFTP_S_IWGRP S_IWGRP +#define LIBSSH2_SFTP_S_IXGRP S_IXGRP +#define LIBSSH2_SFTP_S_IWOTH S_IWOTH +#define LIBSSH2_SFTP_S_IXOTH S_IXOTH +#endif + +static LIBSSH2_ALLOC_FUNC(libssh2_malloc); +static LIBSSH2_REALLOC_FUNC(libssh2_realloc); +static LIBSSH2_FREE_FUNC(libssh2_free); + +static void +kbd_callback(const char *name, int name_len, const char *instruction, + int instruction_len, int num_prompts, + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, + void **abstract) +{ + struct SSHPROTO *ssh = (struct SSHPROTO *)*abstract; + +#ifdef CURL_LIBSSH2_DEBUG + fprintf(stderr, "name=%s\n", name); + fprintf(stderr, "name_len=%d\n", name_len); + fprintf(stderr, "instruction=%s\n", instruction); + fprintf(stderr, "instruction_len=%d\n", instruction_len); + fprintf(stderr, "num_prompts=%d\n", num_prompts); +#else + (void)name; + (void)name_len; + (void)instruction; + (void)instruction_len; +#endif /* CURL_LIBSSH2_DEBUG */ + if (num_prompts == 1) { + responses[0].text = strdup(ssh->passwd); + responses[0].length = strlen(ssh->passwd); + } + (void)prompts; + (void)abstract; +} /* kbd_callback */ + +static CURLcode libssh2_error_to_CURLE(struct connectdata *conn) +{ + int errorcode; + struct SSHPROTO *scp = conn->data->reqdata.proto.ssh; + + /* Get the libssh2 error code and string */ + errorcode = libssh2_session_last_error(scp->ssh_session, &scp->errorstr, + NULL, 0); + if (errorcode == LIBSSH2_FX_OK) + return CURLE_OK; + + infof(conn->data, "libssh2 error %d, '%s'\n", errorcode, scp->errorstr); + + /* TODO: map some of the libssh2 errors to the more appropriate CURLcode + error code, and possibly add a few new SSH-related one. We must however + not return or even depend on libssh2 errors in the public libcurl API */ + + return CURLE_SSH; +} + +static LIBSSH2_ALLOC_FUNC(libssh2_malloc) +{ + return malloc(count); + (void)abstract; +} + +static LIBSSH2_REALLOC_FUNC(libssh2_realloc) +{ + return realloc(ptr, count); + (void)abstract; +} + +static LIBSSH2_FREE_FUNC(libssh2_free) +{ + free(ptr); + (void)abstract; +} + +static CURLcode ssh_init(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + struct SSHPROTO *ssh; + if (data->reqdata.proto.ssh) + return CURLE_OK; + + ssh = (struct SSHPROTO *)calloc(sizeof(struct SSHPROTO), 1); + if (!ssh) + return CURLE_OUT_OF_MEMORY; + + data->reqdata.proto.ssh = ssh; + + /* get some initial data into the ssh struct */ + ssh->bytecountp = &data->reqdata.keep.bytecount; + + /* no need to duplicate them, this connectdata struct won't change */ + ssh->user = conn->user; + ssh->passwd = conn->passwd; + + ssh->errorstr = NULL; + + ssh->ssh_session = NULL; + ssh->ssh_channel = NULL; + ssh->sftp_session = NULL; + ssh->sftp_handle = NULL; + + return CURLE_OK; +} + +/* + * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to + * do protocol-specific actions at connect-time. + */ +CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done) +{ + int i; + struct SSHPROTO *ssh; + const char *fingerprint; + const char *authlist; + char *home; + char rsa_pub[PATH_MAX]; + char rsa[PATH_MAX]; + char tempHome[PATH_MAX]; + curl_socket_t sock; + char *real_path; + char *working_path; + int working_path_len; + bool authed = FALSE; + CURLcode result; + struct SessionHandle *data = conn->data; + + rsa_pub[0] = rsa[0] = '\0'; + + result = ssh_init(conn); + if (result) + return result; + + ssh = data->reqdata.proto.ssh; + + working_path = curl_easy_unescape(data, data->reqdata.path, 0, + &working_path_len); + if (!working_path) + return CURLE_OUT_OF_MEMORY; + +#ifdef CURL_LIBSSH2_DEBUG + if (ssh->user) { + infof(data, "User: %s\n", ssh->user); + } + if (ssh->passwd) { + infof(data, "Password: %s\n", ssh->passwd); + } +#endif /* CURL_LIBSSH2_DEBUG */ + sock = conn->sock[FIRSTSOCKET]; + ssh->ssh_session = libssh2_session_init_ex(libssh2_malloc, libssh2_free, + libssh2_realloc, ssh); + if (ssh->ssh_session == NULL) { + failf(data, "Failure initialising ssh session\n"); + Curl_safefree(ssh->path); + return CURLE_FAILED_INIT; + } +#ifdef CURL_LIBSSH2_DEBUG + infof(data, "SSH socket: %d\n", sock); +#endif /* CURL_LIBSSH2_DEBUG */ + + if (libssh2_session_startup(ssh->ssh_session, sock)) { + failf(data, "Failure establishing ssh session\n"); + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + Curl_safefree(ssh->path); + return CURLE_FAILED_INIT; + } + + /* + * Before we authenticate we should check the hostkey's fingerprint against + * our known hosts. How that is handled (reading from file, whatever) is + * up to us. As for know not much is implemented, besides showing how to + * get the fingerprint. + */ + fingerprint = libssh2_hostkey_hash(ssh->ssh_session, + LIBSSH2_HOSTKEY_HASH_MD5); + +#ifdef CURL_LIBSSH2_DEBUG + /* The fingerprint points to static storage (!), don't free() it. */ + infof(data, "Fingerprint: "); + for (i = 0; i < 16; i++) { + infof(data, "%02X ", (unsigned char) fingerprint[i]); + } + infof(data, "\n"); +#endif /* CURL_LIBSSH2_DEBUG */ + + /* TBD - methods to check the host keys need to be done */ + + /* + * Figure out authentication methods + * NB: As soon as we have provided a username to an openssh server we 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 won't work in my experience. + * So always specify it here. + */ + authlist = libssh2_userauth_list(ssh->ssh_session, ssh->user, + strlen(ssh->user)); + + /* + * Check the supported auth types in the order I feel is most secure with the + * requested type of authentication + */ + if ((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && + (strstr(authlist, "publickey") != NULL)) { + /* To ponder about: should really the lib be messing about with the HOME + environment variable etc? */ + home = curl_getenv("HOME"); + + if (data->set.ssh_public_key) + snprintf(rsa_pub, sizeof(rsa_pub), "%s", data->set.ssh_public_key); + else if (home) + snprintf(rsa_pub, sizeof(rsa_pub), "%s/.ssh/id_dsa.pub", home); + + if (data->set.ssh_private_key) + snprintf(rsa, sizeof(rsa), "%s", data->set.ssh_private_key); + else if (home) + snprintf(rsa, sizeof(rsa), "%s/.ssh/id_dsa", home); + + curl_free(home); + + if (rsa_pub[0]) { + /* The function below checks if the files exists, no need to stat() here. + */ + if (libssh2_userauth_publickey_fromfile(ssh->ssh_session, ssh->user, + rsa_pub, rsa, "") == 0) { + authed = TRUE; + } + } + } + if (!authed && + (data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) && + (strstr(authlist, "password") != NULL)) { + if (!libssh2_userauth_password(ssh->ssh_session, ssh->user, ssh->passwd)) + authed = TRUE; + } + if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_HOST) && + (strstr(authlist, "hostbased") != NULL)) { + } + if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) + && (strstr(authlist, "keyboard-interactive") != NULL)) { + /* Authentication failed. Continue with keyboard-interactive now. */ + if (libssh2_userauth_keyboard_interactive_ex(ssh->ssh_session, ssh->user, + strlen(ssh->user), + &kbd_callback) == 0) { + authed = TRUE; + } + } + + if (!authed) { + failf(data, "Authentication failure\n"); + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + Curl_safefree(ssh->path); + return CURLE_FAILED_INIT; + } + + /* + * At this point we have an authenticated ssh session. + */ + conn->sockfd = sock; + conn->writesockfd = CURL_SOCKET_BAD; + + if (conn->protocol == PROT_SFTP) { + /* + * Start the libssh2 sftp session + */ + ssh->sftp_session = libssh2_sftp_init(ssh->ssh_session); + if (ssh->sftp_session == NULL) { + failf(data, "Failure initialising sftp session\n"); + libssh2_sftp_shutdown(ssh->sftp_session); + ssh->sftp_session = NULL; + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + return CURLE_FAILED_INIT; + } + + /* + * Get the "home" directory + */ + i = libssh2_sftp_realpath(ssh->sftp_session, ".", tempHome, PATH_MAX-1); + if (i > 0) { + /* It seems that this string is not always NULL terminated */ + tempHome[i] = '\0'; + ssh->homedir = (char *)strdup(tempHome); + if (!ssh->homedir) { + libssh2_sftp_shutdown(ssh->sftp_session); + ssh->sftp_session = NULL; + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + return CURLE_OUT_OF_MEMORY; + } + } + else { + /* Return the error type */ + i = libssh2_sftp_last_error(ssh->sftp_session); + DEBUGF(infof(data, "error = %d\n", i)); + } + } + + /* Check for /~/ , indicating realative to the users home directory */ + if (conn->protocol == PROT_SCP) { + real_path = (char *)malloc(working_path_len+1); + if (real_path == NULL) { + Curl_safefree(working_path); + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + return CURLE_OUT_OF_MEMORY; + } + if (working_path[1] == '~') + /* It is referenced to the home directory, so strip the leading '/' */ + memcpy(real_path, working_path+1, 1 + working_path_len-1); + else + memcpy(real_path, working_path, 1 + working_path_len); + } + else if (conn->protocol == PROT_SFTP) { + if (working_path[1] == '~') { + real_path = (char *)malloc(strlen(ssh->homedir) + + working_path_len + 1); + if (real_path == NULL) { + libssh2_sftp_shutdown(ssh->sftp_session); + ssh->sftp_session = NULL; + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + Curl_safefree(working_path); + return CURLE_OUT_OF_MEMORY; + } + /* It is referenced to the home directory, so strip the leading '/' */ + memcpy(real_path, ssh->homedir, strlen(ssh->homedir)); + real_path[strlen(ssh->homedir)] = '/'; + real_path[strlen(ssh->homedir)+1] = '\0'; + if (working_path_len > 3) { + memcpy(real_path+strlen(ssh->homedir)+1, working_path + 3, + 1 + working_path_len -3); + } + } + else { + real_path = (char *)malloc(working_path_len+1); + if (real_path == NULL) { + libssh2_session_free(ssh->ssh_session); + ssh->ssh_session = NULL; + Curl_safefree(working_path); + return CURLE_OUT_OF_MEMORY; + } + memcpy(real_path, working_path, 1+working_path_len); + } + } + else + return CURLE_FAILED_INIT; + + Curl_safefree(working_path); + ssh->path = real_path; + + *done = TRUE; + return CURLE_OK; +} + +CURLcode Curl_scp_do(struct connectdata *conn, bool *done) +{ + struct stat sb; + struct SSHPROTO *scp = conn->data->reqdata.proto.ssh; + CURLcode res = CURLE_OK; + + *done = TRUE; /* unconditionally */ + + if (conn->data->set.upload) { + /* + * NOTE!!! libssh2 requires that the destination path is a full path + * that 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. + */ + scp->ssh_channel = libssh2_scp_send_ex(scp->ssh_session, scp->path, + LIBSSH2_SFTP_S_IRUSR| + LIBSSH2_SFTP_S_IWUSR| + LIBSSH2_SFTP_S_IRGRP| + LIBSSH2_SFTP_S_IROTH, + conn->data->set.infilesize, 0, 0); + if (!scp->ssh_channel) + return CURLE_FAILED_INIT; + + /* upload data */ + res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); + } + else { + /* + * We must check the remote file, if it is a directory no vaules will + * be set in sb + */ + curl_off_t bytecount; + memset(&sb, 0, sizeof(struct stat)); + scp->ssh_channel = libssh2_scp_recv(scp->ssh_session, scp->path, &sb); + if (!scp->ssh_channel) { + if ((sb.st_mode == 0) && (sb.st_atime == 0) && (sb.st_mtime == 0) && + (sb.st_size == 0)) { + /* Since sb is still empty, it is likely the file was not found */ + return CURLE_REMOTE_FILE_NOT_FOUND; + } + return libssh2_error_to_CURLE(conn); + } + /* download data */ + bytecount = (curl_off_t) sb.st_size; + conn->data->reqdata.maxdownload = (curl_off_t) sb.st_size; + res = Curl_setup_transfer(conn, FIRSTSOCKET, + bytecount, FALSE, NULL, -1, NULL); + } + + return res; +} + +CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + struct SSHPROTO *scp = conn->data->reqdata.proto.ssh; + (void)premature; /* not used */ + + Curl_safefree(scp->path); + scp->path = NULL; + + if (scp->ssh_channel) { + if (libssh2_channel_close(scp->ssh_channel) < 0) { + infof(conn->data, "Failed to stop libssh2 channel subsystem\n"); + } + } + + if (scp->ssh_session) { + libssh2_session_disconnect(scp->ssh_session, "Shutdown"); + libssh2_session_free(scp->ssh_session); + scp->ssh_session = NULL; + } + + free(conn->data->reqdata.proto.ssh); + conn->data->reqdata.proto.ssh = NULL; + Curl_pgrsDone(conn); + + (void)status; /* unused */ + + return CURLE_OK; +} + +/* return number of received (decrypted) bytes */ +ssize_t Curl_scp_send(struct connectdata *conn, int sockindex, + void *mem, size_t len) +{ + ssize_t nwrite; + + /* libssh2_channel_write() returns int + * + * NOTE: we should not store nor rely on connection-related data to be + * in the SessionHandle struct + */ + nwrite = (ssize_t) + libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel, + mem, len); + (void)sockindex; + return nwrite; +} + +/* + * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return + * a regular CURLcode value. + */ +ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len) +{ + ssize_t nread; + + /* libssh2_channel_read() returns int + * + * NOTE: we should not store nor rely on connection-related data to be + * in the SessionHandle struct + */ + + nread = (ssize_t) + libssh2_channel_read(conn->data->reqdata.proto.ssh->ssh_channel, + mem, len); + (void)sockindex; + return nread; +} + +/* + * =============== SFTP =============== + */ + +CURLcode Curl_sftp_do(struct connectdata *conn, bool *done) +{ + LIBSSH2_SFTP_ATTRIBUTES attrs; + struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh; + CURLcode res = CURLE_OK; + struct SessionHandle *data = conn->data; + curl_off_t bytecount = 0; + char *buf = data->state.buffer; + + *done = TRUE; /* unconditionally */ + + if (data->set.upload) { + /* + * NOTE!!! libssh2 requires that the destination path is a full path + * that 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. + */ + sftp->sftp_handle = + libssh2_sftp_open(sftp->sftp_session, sftp->path, + LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT, + LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR| + LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH); + if (!sftp->sftp_handle) + return CURLE_FAILED_INIT; + + /* upload data */ + res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); + } + else { + if (sftp->path[strlen(sftp->path)-1] == '/') { + /* + * This is a directory that we are trying to get, so produce a + * directory listing + * + * **BLOCKING behaviour** This should be made into a state machine and + * get a separate function called from Curl_sftp_recv() when there is + * data to read from the network, instead of "hanging" here. + */ + char filename[PATH_MAX+1]; + int len, totalLen, currLen; + char *line; + + sftp->sftp_handle = + libssh2_sftp_opendir(sftp->sftp_session, sftp->path); + if (!sftp->sftp_handle) + return CURLE_SSH; + + while ((len = libssh2_sftp_readdir(sftp->sftp_handle, filename, + PATH_MAX, &attrs)) > 0) { + filename[len] = '\0'; + + if (data->set.ftp_list_only) { + if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && + ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFDIR)) { + infof(data, "%s\n", filename); + } + } + else { + totalLen = 80 + len; + line = (char *)malloc(totalLen); + if (!line) + return CURLE_OUT_OF_MEMORY; + + if (!(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID)) + attrs.uid = attrs.gid =0; + + currLen = snprintf(line, totalLen, "---------- 1 %5d %5d", + attrs.uid, attrs.gid); + + if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { + if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFDIR) { + line[0] = 'd'; + } + else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFLNK) { + line[0] = 'l'; + } + else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFSOCK) { + line[0] = 's'; + } + else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFCHR) { + line[0] = 'c'; + } + else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFBLK) { + line[0] = 'b'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IRUSR) { + line[1] = 'r'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IWUSR) { + line[2] = 'w'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IXUSR) { + line[3] = 'x'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IRGRP) { + line[4] = 'r'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IWGRP) { + line[5] = 'w'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IXGRP) { + line[6] = 'x'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IROTH) { + line[7] = 'r'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IWOTH) { + line[8] = 'w'; + } + if (attrs.permissions & LIBSSH2_SFTP_S_IXOTH) { + line[9] = 'x'; + } + } + if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { + currLen += snprintf(line+currLen, totalLen-currLen, "%11lld", + attrs.filesize); + } + if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { + const char *months[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + struct tm *nowParts; + time_t now, remoteTime; + + now = time(NULL); + remoteTime = (time_t)attrs.mtime; + nowParts = localtime(&remoteTime); + + if ((time_t)attrs.mtime > (now - (3600 * 24 * 180))) { + currLen += snprintf(line+currLen, totalLen-currLen, + " %s %2d %2d:%02d", months[nowParts->tm_mon], + nowParts->tm_mday, nowParts->tm_hour, + nowParts->tm_min); + } + else { + currLen += snprintf(line+currLen, totalLen-currLen, + " %s %2d %5d", months[nowParts->tm_mon], + nowParts->tm_mday, 1900+nowParts->tm_year); + } + } + currLen += snprintf(line+currLen, totalLen-currLen, " %s", filename); + if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && + ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == + LIBSSH2_SFTP_S_IFLNK)) { + char linkPath[PATH_MAX + 1]; + + snprintf(linkPath, PATH_MAX, "%s%s", sftp->path, filename); + len = libssh2_sftp_readlink(sftp->sftp_session, linkPath, filename, + PATH_MAX); + line = realloc(line, totalLen + 4 + len); + if (!line) + return CURLE_OUT_OF_MEMORY; + + currLen += snprintf(line+currLen, totalLen-currLen, " -> %s", + filename); + } + + currLen += snprintf(line+currLen, totalLen-currLen, "\n"); + res = Curl_client_write(conn, CLIENTWRITE_BODY, line, 0); + free(line); + } + } + libssh2_sftp_closedir(sftp->sftp_handle); + sftp->sftp_handle = NULL; + + /* no data to transfer */ + res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + } + else { + /* + * Work on getting the specified file + */ + sftp->sftp_handle = + libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_READ, + LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR| + LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH); + if (!sftp->sftp_handle) + return CURLE_SSH; + + if (libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs)) { + /* + * libssh2_sftp_open() didn't return an error, so maybe the server + * just doesn't support stat() + */ + data->reqdata.size = -1; + data->reqdata.maxdownload = -1; + } + else { + data->reqdata.size = attrs.filesize; + data->reqdata.maxdownload = attrs.filesize; + Curl_pgrsSetDownloadSize(data, attrs.filesize); + } + + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + + /* Now download data. The libssh2 0.14 doesn't offer any way to do this + without using this BLOCKING approach, so here's room for improvement + once libssh2 can return EWOULDBLOCK to us. */ +#if 0 + /* code left here just because this is what this function will use the + day libssh2 is improved */ + res = Curl_setup_transfer(conn, FIRSTSOCKET, + bytecount, FALSE, NULL, -1, NULL); +#endif + while (res == CURLE_OK) { + size_t nread; + /* NOTE: most *read() functions return ssize_t but this returns size_t + which normally is unsigned! */ + nread = libssh2_sftp_read(data->reqdata.proto.ssh->sftp_handle, + buf, BUFSIZE-1); + + if (nread > 0) + buf[nread] = 0; + + /* this check can be changed to a <= 0 when nread is changed to a + signed variable type */ + if ((nread == 0) || (nread == (size_t)~0)) + break; + + bytecount += nread; + + res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); + if(res) + return res; + + Curl_pgrsSetDownloadCounter(data, bytecount); + + if(Curl_pgrsUpdate(conn)) + res = CURLE_ABORTED_BY_CALLBACK; + else { + struct timeval now = Curl_tvnow(); + res = Curl_speedcheck(data, now); + } + } + if(Curl_pgrsUpdate(conn)) + res = CURLE_ABORTED_BY_CALLBACK; + + /* no (more) data to transfer */ + res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + } + } + + return res; +} + +CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh; + (void)premature; /* not used */ + + Curl_safefree(sftp->path); + sftp->path = NULL; + + Curl_safefree(sftp->homedir); + sftp->homedir = NULL; + + if (sftp->sftp_handle) { + if (libssh2_sftp_close(sftp->sftp_handle) < 0) { + infof(conn->data, "Failed to close libssh2 file\n"); + } + } + + if (sftp->sftp_session) { + if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) { + infof(conn->data, "Failed to stop libssh2 sftp subsystem\n"); + } + } + + if (sftp->ssh_channel) { + if (libssh2_channel_close(sftp->ssh_channel) < 0) { + infof(conn->data, "Failed to stop libssh2 channel subsystem\n"); + } + } + + if (sftp->ssh_session) { + libssh2_session_disconnect(sftp->ssh_session, "Shutdown"); + libssh2_session_free(sftp->ssh_session); + sftp->ssh_session = NULL; + } + + free(conn->data->reqdata.proto.ssh); + conn->data->reqdata.proto.ssh = NULL; + Curl_pgrsDone(conn); + + (void)status; /* unused */ + + return CURLE_OK; +} + +/* return number of received (decrypted) bytes */ +ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex, + void *mem, size_t len) +{ + ssize_t nwrite; + + /* libssh2_sftp_write() returns size_t !*/ + + nwrite = (ssize_t) + libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); + (void)sockindex; + return nwrite; +} + +/* + * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return + * a regular CURLcode value. + */ +ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len) +{ + ssize_t nread; + + /* libssh2_sftp_read() returns size_t !*/ + + nread = (ssize_t) + libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); + (void)sockindex; + return nread; +} + +#endif /* USE_LIBSSH2 */ diff --git a/Utilities/cmcurl/lib/ssh.h b/Utilities/cmcurl/lib/ssh.h new file mode 100644 index 0000000..d914490 --- /dev/null +++ b/Utilities/cmcurl/lib/ssh.h @@ -0,0 +1,49 @@ +#ifndef __SSH_H +#define __SSH_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifdef USE_LIBSSH2 + +CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done); + +CURLcode Curl_scp_do(struct connectdata *conn, bool *done); +CURLcode Curl_scp_done(struct connectdata *conn, CURLcode, bool premature); + +ssize_t Curl_scp_send(struct connectdata *conn, int sockindex, + void *mem, size_t len); +ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len); + +CURLcode Curl_sftp_do(struct connectdata *conn, bool *done); +CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode, bool premature); + +ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex, + void *mem, size_t len); +ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len); + +#endif /* USE_LIBSSH2 */ + +#endif /* __SSH_H */ diff --git a/Utilities/cmcurl/lib/sslgen.c b/Utilities/cmcurl/lib/sslgen.c new file mode 100644 index 0000000..f110a51 --- /dev/null +++ b/Utilities/cmcurl/lib/sslgen.c @@ -0,0 +1,618 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* This file is for "generic" SSL functions that all libcurl internals should + use. It is responsible for calling the proper 'ossl' function in ssluse.c + (OpenSSL based) or the 'gtls' function in gtls.c (GnuTLS based). + + SSL-functions in libcurl should call functions in this source file, and not + to any specific SSL-layer. + + Curl_ssl_ - prefix for generic ones + Curl_ossl_ - prefix for OpenSSL ones + Curl_gtls_ - prefix for GnuTLS ones + + "SSL/TLS Strong Encryption: An Introduction" + http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html +*/ + +#include "setup.h" +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "urldata.h" +#define SSLGEN_C +#include "sslgen.h" /* generic SSL protos etc */ +#include "ssluse.h" /* OpenSSL versions */ +#include "gtls.h" /* GnuTLS versions */ +#include "sendf.h" +#include "strequal.h" +#include "url.h" +#include "memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* "global" init done? */ +static bool init_ssl=FALSE; + +static bool safe_strequal(char* str1, char* str2); + +static bool safe_strequal(char* str1, char* str2) +{ + if(str1 && str2) + /* both pointers point to something then compare them */ + return (bool)(0 != strequal(str1, str2)); + else + /* if both pointers are NULL then treat them as equal */ + return (bool)(!str1 && !str2); +} + +bool +Curl_ssl_config_matches(struct ssl_config_data* data, + struct ssl_config_data* needle) +{ + if((data->version == needle->version) && + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + safe_strequal(data->CApath, needle->CApath) && + safe_strequal(data->CAfile, needle->CAfile) && + safe_strequal(data->random_file, needle->random_file) && + safe_strequal(data->egdsocket, needle->egdsocket) && + safe_strequal(data->cipher_list, needle->cipher_list)) + return TRUE; + + return FALSE; +} + +bool +Curl_clone_ssl_config(struct ssl_config_data *source, + struct ssl_config_data *dest) +{ + dest->verifyhost = source->verifyhost; + dest->verifypeer = source->verifypeer; + dest->version = source->version; + + if(source->CAfile) { + dest->CAfile = strdup(source->CAfile); + if(!dest->CAfile) + return FALSE; + } + + if(source->CApath) { + dest->CApath = strdup(source->CApath); + if(!dest->CApath) + return FALSE; + } + + if(source->cipher_list) { + dest->cipher_list = strdup(source->cipher_list); + if(!dest->cipher_list) + return FALSE; + } + + if(source->egdsocket) { + dest->egdsocket = strdup(source->egdsocket); + if(!dest->egdsocket) + return FALSE; + } + + if(source->random_file) { + dest->random_file = strdup(source->random_file); + if(!dest->random_file) + return FALSE; + } + + return TRUE; +} + +void Curl_free_ssl_config(struct ssl_config_data* sslc) +{ + if(sslc->CAfile) + free(sslc->CAfile); + + if(sslc->CApath) + free(sslc->CApath); + + if(sslc->cipher_list) + free(sslc->cipher_list); + + if(sslc->egdsocket) + free(sslc->egdsocket); + + if(sslc->random_file) + free(sslc->random_file); +} + +/** + * Global SSL init + * + * @retval 0 error initializing SSL + * @retval 1 SSL initialized successfully + */ +int Curl_ssl_init(void) +{ + /* make sure this is only done once */ + if(init_ssl) + return 1; + init_ssl = TRUE; /* never again */ + +#ifdef USE_SSLEAY + return Curl_ossl_init(); +#else +#ifdef USE_GNUTLS + return Curl_gtls_init(); +#else + /* no SSL support */ + return 1; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +} + + +/* Global cleanup */ +void Curl_ssl_cleanup(void) +{ + if(init_ssl) { + /* only cleanup if we did a previous init */ +#ifdef USE_SSLEAY + Curl_ossl_cleanup(); +#else +#ifdef USE_GNUTLS + Curl_gtls_cleanup(); +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ + init_ssl = FALSE; + } +} + +CURLcode +Curl_ssl_connect(struct connectdata *conn, int sockindex) +{ +#ifdef USE_SSL + /* mark this is being ssl enabled from here on. */ + conn->ssl[sockindex].use = TRUE; + +#ifdef USE_SSLEAY + return Curl_ossl_connect(conn, sockindex); +#else +#ifdef USE_GNUTLS + return Curl_gtls_connect(conn, sockindex); +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ + +#else + /* without SSL */ + (void)conn; + (void)sockindex; + return CURLE_OK; +#endif /* USE_SSL */ +} + +CURLcode +Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, + bool *done) +{ +#if defined(USE_SSL) && defined(USE_SSLEAY) + /* mark this is being ssl enabled from here on. */ + conn->ssl[sockindex].use = TRUE; + return Curl_ossl_connect_nonblocking(conn, sockindex, done); + +#else + /* not implemented! + fallback to BLOCKING call. */ + *done = TRUE; + return Curl_ssl_connect(conn, sockindex); +#endif +} + +#ifdef USE_SSL + +/* + * 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. + */ +int Curl_ssl_getsessionid(struct connectdata *conn, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */ +{ + struct curl_ssl_session *check; + struct SessionHandle *data = conn->data; + long i; + + if(!conn->ssl_config.sessionid) + /* session ID re-use is disabled */ + return TRUE; + + for(i=0; i< data->set.ssl.numsessions; i++) { + check = &data->state.session[i]; + if(!check->sessionid) + /* not session ID means blank entry */ + continue; + if(curl_strequal(conn->host.name, check->name) && + (conn->remote_port == check->remote_port) && + Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { + /* yes, we have a session ID! */ + data->state.sessionage++; /* increase general age */ + check->age = data->state.sessionage; /* set this as used in this age */ + *ssl_sessionid = check->sessionid; + if(idsize) + *idsize = check->idsize; + return FALSE; + } + } + *ssl_sessionid = NULL; + return TRUE; +} + +/* + * Kill a single session ID entry in the cache. + */ +static int kill_session(struct curl_ssl_session *session) +{ + if(session->sessionid) { + /* defensive check */ + + /* free the ID the SSL-layer specific way */ +#ifdef USE_SSLEAY + Curl_ossl_session_free(session->sessionid); +#else + Curl_gtls_session_free(session->sessionid); +#endif + session->sessionid=NULL; + session->age = 0; /* fresh */ + + Curl_free_ssl_config(&session->ssl_config); + + Curl_safefree(session->name); + session->name = NULL; /* no name */ + + return 0; /* ok */ + } + else + return 1; +} + +/* + * 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 connectdata *conn, + void *ssl_sessionid, + size_t idsize) +{ + int i; + struct SessionHandle *data=conn->data; /* the mother of all structs */ + struct curl_ssl_session *store = &data->state.session[0]; + long oldest_age=data->state.session[0].age; /* zero if unused */ + char *clone_host; + + /* Even though session ID re-use might be disabled, that only disables USING + IT. We still store it here in case the re-using is again enabled for an + upcoming transfer */ + + clone_host = strdup(conn->host.name); + if(!clone_host) + return CURLE_OUT_OF_MEMORY; /* bail out */ + + /* Now we should add the session ID and the host name to the cache, (remove + the oldest if necessary) */ + + /* find an empty slot for us, or find the oldest */ + for(i=1; (iset.ssl.numsessions) && + data->state.session[i].sessionid; i++) { + if(data->state.session[i].age < oldest_age) { + oldest_age = data->state.session[i].age; + store = &data->state.session[i]; + } + } + if(i == data->set.ssl.numsessions) + /* cache is full, we must "kill" the oldest entry! */ + kill_session(store); + else + store = &data->state.session[i]; /* use this slot */ + + /* now init the session struct wisely */ + store->sessionid = ssl_sessionid; + store->idsize = idsize; + store->age = data->state.sessionage; /* set current age */ + store->name = clone_host; /* clone host name */ + store->remote_port = conn->remote_port; /* port number */ + + if (!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + + +#endif + +void Curl_ssl_close_all(struct SessionHandle *data) +{ +#ifdef USE_SSL + int i; + /* kill the session ID cache */ + if(data->state.session) { + for(i=0; i< data->set.ssl.numsessions; i++) + /* the single-killer function handles empty table slots */ + kill_session(&data->state.session[i]); + + /* free the cache data */ + free(data->state.session); + data->state.session = NULL; + } +#ifdef USE_SSLEAY + Curl_ossl_close_all(data); +#else +#ifdef USE_GNUTLS + Curl_gtls_close_all(data); +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +#else /* USE_SSL */ + (void)data; +#endif /* USE_SSL */ +} + +void Curl_ssl_close(struct connectdata *conn) +{ + if(conn->ssl[FIRSTSOCKET].use) { +#ifdef USE_SSLEAY + Curl_ossl_close(conn); +#else +#ifdef USE_GNUTLS + Curl_gtls_close(conn); +#else + (void)conn; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ + } +} + +CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) +{ + if(conn->ssl[sockindex].use) { +#ifdef USE_SSLEAY + if(Curl_ossl_shutdown(conn, sockindex)) + return CURLE_SSL_SHUTDOWN_FAILED; +#else +#ifdef USE_GNUTLS + if(Curl_gtls_shutdown(conn, sockindex)) + return CURLE_SSL_SHUTDOWN_FAILED; +#else + (void)conn; + (void)sockindex; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ + } + return CURLE_OK; +} + +/* Selects an (Open)SSL crypto engine + */ +CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) +{ +#ifdef USE_SSLEAY + return Curl_ossl_set_engine(data, engine); +#else +#ifdef USE_GNUTLS + /* FIX: add code here */ + (void)data; + (void)engine; + return CURLE_FAILED_INIT; +#else + /* no SSL layer */ + (void)data; + (void)engine; + return CURLE_FAILED_INIT; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +} + +/* Selects an (Open?)SSL crypto engine + */ +CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) +{ +#ifdef USE_SSLEAY + return Curl_ossl_set_engine_default(data); +#else +#ifdef USE_GNUTLS + /* FIX: add code here */ + (void)data; + return CURLE_FAILED_INIT; +#else + /* No SSL layer */ + (void)data; + return CURLE_FAILED_INIT; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +} + +/* Return list of OpenSSL crypto engine names. */ +struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) +{ +#ifdef USE_SSLEAY + return Curl_ossl_engines_list(data); +#else +#ifdef USE_GNUTLS + /* FIX: add code here? */ + (void)data; + return NULL; +#else + (void)data; + return NULL; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +} + +/* return number of sent (non-SSL) bytes */ +ssize_t Curl_ssl_send(struct connectdata *conn, + int sockindex, + void *mem, + size_t len) +{ +#ifdef USE_SSLEAY + return Curl_ossl_send(conn, sockindex, mem, len); +#else +#ifdef USE_GNUTLS + return Curl_gtls_send(conn, sockindex, mem, len); +#else + (void)conn; + (void)sockindex; + (void)mem; + (void)len; + return 0; +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +} + +/* return number of received (decrypted) bytes */ + +/* + * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return + * a regular CURLcode value. + */ +ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */ + int sockindex, /* socketindex */ + char *mem, /* store read data here */ + size_t len) /* max amount to read */ +{ +#ifdef USE_SSL + ssize_t nread; + bool block = FALSE; + +#ifdef USE_SSLEAY + nread = Curl_ossl_recv(conn, sockindex, mem, len, &block); +#else +#ifdef USE_GNUTLS + nread = Curl_gtls_recv(conn, sockindex, mem, len, &block); +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ + if(nread == -1) { + if(!block) + return 0; /* this is a true error, not EWOULDBLOCK */ + else + return -1; + } + + return (int)nread; + +#else /* USE_SSL */ + (void)conn; + (void)sockindex; + (void)mem; + (void)len; + return 0; +#endif /* USE_SSL */ +} + + +/* + * This sets up a session ID cache to the specified size. Make sure this code + * is agnostic to what underlying SSL technology we use. + */ +CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount) +{ +#ifdef USE_SSL + struct curl_ssl_session *session; + + if(data->state.session) + /* this is just a precaution to prevent multiple inits */ + return CURLE_OK; + + session = (struct curl_ssl_session *) + calloc(sizeof(struct curl_ssl_session), amount); + if(!session) + return CURLE_OUT_OF_MEMORY; + + /* store the info in the SSL section */ + data->set.ssl.numsessions = amount; + data->state.session = session; + data->state.sessionage = 1; /* this is brand new */ +#else + /* without SSL, do nothing */ + (void)data; + (void)amount; +#endif + + return CURLE_OK; +} + +size_t Curl_ssl_version(char *buffer, size_t size) +{ +#ifdef USE_SSLEAY + return Curl_ossl_version(buffer, size); +#else +#ifdef USE_GNUTLS + return Curl_gtls_version(buffer, size); +#else + (void)buffer; + (void)size; + return 0; /* no SSL support */ +#endif /* USE_GNUTLS */ +#endif /* USE_SSLEAY */ +} + + +/* + * This function tries to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int Curl_ssl_check_cxn(struct connectdata *conn) +{ +#ifdef USE_SSLEAY + return Curl_ossl_check_cxn(conn); +#else + (void)conn; + /* TODO: we lack implementation of this for GnuTLS */ + return -1; /* connection status unknown */ +#endif /* USE_SSLEAY */ +} + +bool Curl_ssl_data_pending(struct connectdata *conn, + int connindex) +{ +#ifdef USE_SSLEAY + /* OpenSSL-specific */ + if(conn->ssl[connindex].handle) + /* SSL is in use */ + return SSL_pending(conn->ssl[connindex].handle); +#else + (void)conn; + (void)connindex; +#endif + return FALSE; /* nothing pending */ + +} diff --git a/Utilities/cmcurl/lib/sslgen.h b/Utilities/cmcurl/lib/sslgen.h new file mode 100644 index 0000000..c24d46b --- /dev/null +++ b/Utilities/cmcurl/lib/sslgen.h @@ -0,0 +1,84 @@ +#ifndef __SSLGEN_H +#define __SSLGEN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +bool Curl_ssl_config_matches(struct ssl_config_data* data, + struct ssl_config_data* needle); +bool Curl_clone_ssl_config(struct ssl_config_data* source, + struct ssl_config_data* dest); +void Curl_free_ssl_config(struct ssl_config_data* sslc); + +int Curl_ssl_init(void); +void Curl_ssl_cleanup(void); +CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex); +CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); +void Curl_ssl_close(struct connectdata *conn); +/* tell the SSL stuff to close down all open information regarding + connections (and thus session ID caching etc) */ +void Curl_ssl_close_all(struct SessionHandle *data); +CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine); +/* Sets engine as default for all SSL operations */ +CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data); +ssize_t Curl_ssl_send(struct connectdata *conn, + int sockindex, + void *mem, + size_t len); +ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */ + int sockindex, /* socketindex */ + char *mem, /* store read data here */ + size_t len); /* max amount to read */ + +/* init the SSL session ID cache */ +CURLcode Curl_ssl_initsessions(struct SessionHandle *, long); +/* extract a session ID */ +int Curl_ssl_getsessionid(struct connectdata *conn, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */; +/* add a new session ID */ +CURLcode Curl_ssl_addsessionid(struct connectdata *conn, + void *ssl_sessionid, + size_t idsize); + + +struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data); + +size_t Curl_ssl_version(char *buffer, size_t size); + +int Curl_ssl_check_cxn(struct connectdata *conn); + +CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); + +bool Curl_ssl_data_pending(struct connectdata *conn, + int connindex); + +#if !defined(USE_SSL) && !defined(SSLGEN_C) +/* set up blank macros for none-SSL builds */ +#define Curl_ssl_close_all(x) +#endif + +#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ + +#endif diff --git a/Utilities/cmcurl/lib/ssluse.c b/Utilities/cmcurl/lib/ssluse.c new file mode 100644 index 0000000..6709278 --- /dev/null +++ b/Utilities/cmcurl/lib/ssluse.c @@ -0,0 +1,1950 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code + * but sslgen.c should ever call or use these functions. + */ + +/* + * The original SSLeay-using code for curl was written by Linas Vepstas and + * Sampo Kellomaki 1998. + */ + +#include "setup.h" + +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "formdata.h" /* for the boundary function */ +#include "url.h" /* for the ssl config check function */ +#include "inet_pton.h" +#include "ssluse.h" +#include "connect.h" /* Curl_sockerrno() proto */ +#include "strequal.h" +#include "select.h" +#include "sslgen.h" + +#define _MPRINTF_REPLACE /* use the internal *printf() functions */ +#include + +#ifdef USE_SSLEAY + +#ifdef USE_OPENSSL +#include +#include +#else +#include +#include +#endif + +#include "memory.h" +#include "easyif.h" /* for Curl_convert_from_utf8 prototype */ + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x0090581fL +#define HAVE_SSL_GET1_SESSION 1 +#else +#undef HAVE_SSL_GET1_SESSION +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x00904100L +#define HAVE_USERDATA_IN_PWD_CALLBACK 1 +#else +#undef HAVE_USERDATA_IN_PWD_CALLBACK +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x00907001L +/* ENGINE_load_private_key() takes four arguments */ +#define HAVE_ENGINE_LOAD_FOUR_ARGS +#else +/* ENGINE_load_private_key() takes three arguments */ +#undef HAVE_ENGINE_LOAD_FOUR_ARGS +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H) +/* OpenSSL has PKCS 12 support */ +#define HAVE_PKCS12_SUPPORT +#else +/* OpenSSL/SSLEay does not have PKCS12 support */ +#undef HAVE_PKCS12_SUPPORT +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x00906001L +#define HAVE_ERR_ERROR_STRING_N 1 +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x00909000L +#define SSL_METHOD_QUAL const +#else +#define SSL_METHOD_QUAL +#endif + +/* + * Number of bytes to read from the random number seed file. This must be + * a finite value (because some entropy "files" like /dev/urandom have + * an infinite length), but must be large enough to provide enough + * entopy to properly seed OpenSSL's PRNG. + */ +#define RAND_LOAD_LENGTH 1024 + +#ifndef HAVE_USERDATA_IN_PWD_CALLBACK +static char global_passwd[64]; +#endif + +static int passwd_callback(char *buf, int num, int verify +#if HAVE_USERDATA_IN_PWD_CALLBACK + /* This was introduced in 0.9.4, we can set this + using SSL_CTX_set_default_passwd_cb_userdata() + */ + , void *global_passwd +#endif + ) +{ + if(verify) + fprintf(stderr, "%s\n", buf); + else { + if(num > (int)strlen((char *)global_passwd)) { + strcpy(buf, global_passwd); + return (int)strlen(buf); + } + } + return 0; +} + +/* + * rand_enough() is a function that returns TRUE if we have seeded the random + * engine properly. We use some preprocessor magic to provide a seed_enough() + * macro to use, just to prevent a compiler warning on this function if we + * pass in an argument that is never used. + */ + +#ifdef HAVE_RAND_STATUS +#define seed_enough(x) rand_enough() +static bool rand_enough(void) +{ + return (bool)(0 != RAND_status()); +} +#else +#define seed_enough(x) rand_enough(x) +static bool rand_enough(int nread) +{ + /* this is a very silly decision to make */ + return (bool)(nread > 500); +} +#endif + +static int ossl_seed(struct SessionHandle *data) +{ + char *buf = data->state.buffer; /* point to the big buffer */ + int nread=0; + + /* Q: should we add support for a random file name as a libcurl option? + A: Yes, it is here */ + +#ifndef RANDOM_FILE + /* if RANDOM_FILE isn't defined, we only perform this if an option tells + us to! */ + if(data->set.ssl.random_file) +#define RANDOM_FILE "" /* doesn't matter won't be used */ +#endif + { + /* let the option override the define */ + nread += RAND_load_file((data->set.ssl.random_file? + data->set.ssl.random_file:RANDOM_FILE), + RAND_LOAD_LENGTH); + if(seed_enough(nread)) + return nread; + } + +#if defined(HAVE_RAND_EGD) + /* only available in OpenSSL 0.9.5 and later */ + /* EGD_SOCKET is set at configure time or not at all */ +#ifndef EGD_SOCKET + /* If we don't have the define set, we only do this if the egd-option + is set */ + if(data->set.ssl.egdsocket) +#define EGD_SOCKET "" /* doesn't matter won't be used */ +#endif + { + /* If there's an option and a define, the option overrides the + define */ + int ret = RAND_egd(data->set.ssl.egdsocket? + data->set.ssl.egdsocket:EGD_SOCKET); + if(-1 != ret) { + nread += ret; + if(seed_enough(nread)) + return nread; + } + } +#endif + + /* If we get here, it means we need to seed the PRNG using a "silly" + approach! */ +#ifdef HAVE_RAND_SCREEN + /* This one gets a random value by reading the currently shown screen */ + RAND_screen(); + nread = 100; /* just a value */ +#else + { + int len; + char *area; + + /* Changed call to RAND_seed to use the underlying RAND_add implementation + * directly. Do this in a loop, with the amount of additional entropy + * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes + * of a 7-bit ascii set. -- Richard Gorton, March 11 2003. + */ + + do { + area = Curl_FormBoundary(); + if(!area) + return 3; /* out of memory */ + + len = (int)strlen(area); + RAND_add(area, len, (len >> 1)); + + free(area); /* now remove the random junk */ + } while (!RAND_status()); + } +#endif + + /* generates a default path for the random seed file */ + buf[0]=0; /* blank it first */ + RAND_file_name(buf, BUFSIZE); + if(buf[0]) { + /* we got a file name to try */ + nread += RAND_load_file(buf, RAND_LOAD_LENGTH); + if(seed_enough(nread)) + return nread; + } + + infof(data, "libcurl is now using a weak random seed!\n"); + return nread; +} + +int Curl_ossl_seed(struct SessionHandle *data) +{ + /* we have the "SSL is seeded" boolean static to prevent multiple + time-consuming seedings in vain */ + static bool ssl_seeded = FALSE; + + if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { + ossl_seed(data); + ssl_seeded = TRUE; + } + return 0; +} + + +#ifndef SSL_FILETYPE_ENGINE +#define SSL_FILETYPE_ENGINE 42 +#endif +#ifndef SSL_FILETYPE_PKCS12 +#define SSL_FILETYPE_PKCS12 43 +#endif +static int do_file_type(const char *type) +{ + if(!type || !type[0]) + return SSL_FILETYPE_PEM; + if(curl_strequal(type, "PEM")) + return SSL_FILETYPE_PEM; + if(curl_strequal(type, "DER")) + return SSL_FILETYPE_ASN1; + if(curl_strequal(type, "ENG")) + return SSL_FILETYPE_ENGINE; + if(curl_strequal(type, "P12")) + return SSL_FILETYPE_PKCS12; + return -1; +} + +static +int cert_stuff(struct connectdata *conn, + SSL_CTX* ctx, + char *cert_file, + const char *cert_type, + char *key_file, + const char *key_type) +{ + struct SessionHandle *data = conn->data; + int file_type; + + if(cert_file != NULL) { + SSL *ssl; + X509 *x509; + int cert_done = 0; + + if(data->set.key_passwd) { +#ifndef HAVE_USERDATA_IN_PWD_CALLBACK + /* + * If password has been given, we store that in the global + * area (*shudder*) for a while: + */ + size_t len = strlen(data->set.key_passwd); + if(len < sizeof(global_passwd)) + memcpy(global_passwd, data->set.key_passwd, len+1); +#else + /* + * We set the password in the callback userdata + */ + SSL_CTX_set_default_passwd_cb_userdata(ctx, + data->set.key_passwd); +#endif + /* Set passwd callback: */ + SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); + } + + file_type = do_file_type(cert_type); + +#define SSL_CLIENT_CERT_ERR \ + "unable to use client certificate (no key found or wrong pass phrase?)" + + switch(file_type) { + case SSL_FILETYPE_PEM: + /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ + if(SSL_CTX_use_certificate_chain_file(ctx, + cert_file) != 1) { + failf(data, SSL_CLIENT_CERT_ERR); + return 0; + } + break; + + case SSL_FILETYPE_ASN1: + /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but + we use the case above for PEM so this can only be performed with + ASN1 files. */ + if(SSL_CTX_use_certificate_file(ctx, + cert_file, + file_type) != 1) { + failf(data, SSL_CLIENT_CERT_ERR); + return 0; + } + break; + case SSL_FILETYPE_ENGINE: + failf(data, "file type ENG for certificate not implemented"); + return 0; + + case SSL_FILETYPE_PKCS12: + { +#ifdef HAVE_PKCS12_SUPPORT + FILE *f; + PKCS12 *p12; + EVP_PKEY *pri; + + f = fopen(cert_file,"rb"); + if (!f) { + failf(data, "could not open PKCS12 file '%s'", cert_file); + return 0; + } + p12 = d2i_PKCS12_fp(f, NULL); + fclose(f); + + PKCS12_PBE_add(); + + if (!PKCS12_parse(p12, data->set.key_passwd, &pri, &x509, NULL)) { + failf(data, + "could not parse PKCS12 file, check password, OpenSSL error %s", + ERR_error_string(ERR_get_error(), NULL) ); + return 0; + } + + PKCS12_free(p12); + + if(SSL_CTX_use_certificate(ctx, x509) != 1) { + failf(data, SSL_CLIENT_CERT_ERR); + EVP_PKEY_free(pri); + X509_free(x509); + return 0; + } + + if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { + failf(data, "unable to use private key from PKCS12 file '%s'", + cert_file); + EVP_PKEY_free(pri); + X509_free(x509); + return 0; + } + + EVP_PKEY_free(pri); + X509_free(x509); + cert_done = 1; + break; +#else + failf(data, "file type P12 for certificate not supported"); + return 0; +#endif + } + default: + failf(data, "not supported file type '%s' for certificate", cert_type); + return 0; + } + + file_type = do_file_type(key_type); + + switch(file_type) { + case SSL_FILETYPE_PEM: + if(cert_done) + break; + if(key_file == NULL) + /* cert & key can only be in PEM case in the same file */ + key_file=cert_file; + case SSL_FILETYPE_ASN1: + if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { + failf(data, "unable to set private key file: '%s' type %s\n", + key_file, key_type?key_type:"PEM"); + return 0; + } + break; + case SSL_FILETYPE_ENGINE: +#ifdef HAVE_OPENSSL_ENGINE_H + { /* XXXX still needs some work */ + EVP_PKEY *priv_key = NULL; + if(conn && conn->data && conn->data->state.engine) { +#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS + UI_METHOD *ui_method = UI_OpenSSL(); +#endif + if(!key_file || !key_file[0]) { + failf(data, "no key set to load from crypto engine\n"); + return 0; + } + /* the typecast below was added to please MinGW32 */ + priv_key = (EVP_PKEY *) + ENGINE_load_private_key(conn->data->state.engine,key_file, +#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS + ui_method, +#endif + data->set.key_passwd); + if(!priv_key) { + failf(data, "failed to load private key from crypto engine\n"); + return 0; + } + if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { + failf(data, "unable to set private key\n"); + EVP_PKEY_free(priv_key); + return 0; + } + EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ + } + else { + failf(data, "crypto engine not set, can't load private key\n"); + return 0; + } + } + break; +#else + failf(data, "file type ENG for private key not supported\n"); + return 0; +#endif + case SSL_FILETYPE_PKCS12: + if(!cert_done) { + failf(data, "file type P12 for private key not supported\n"); + return 0; + } + break; + default: + failf(data, "not supported file type for private key\n"); + return 0; + } + + ssl=SSL_new(ctx); + if (NULL == ssl) { + failf(data,"unable to create an SSL structure\n"); + return 0; + } + + x509=SSL_get_certificate(ssl); + + /* This version was provided by Evan Jordan and is supposed to not + leak memory as the previous version: */ + if(x509 != NULL) { + EVP_PKEY *pktmp = X509_get_pubkey(x509); + EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl)); + EVP_PKEY_free(pktmp); + } + + SSL_free(ssl); + + /* If we are using DSA, we can copy the parameters from + * the private key */ + + + /* Now we know that a key and cert have been set against + * the SSL context */ + if(!SSL_CTX_check_private_key(ctx)) { + failf(data, "Private key does not match the certificate public key"); + return(0); + } +#ifndef HAVE_USERDATA_IN_PWD_CALLBACK + /* erase it now */ + memset(global_passwd, 0, sizeof(global_passwd)); +#endif + } + return(1); +} + +static +int cert_verify_callback(int ok, X509_STORE_CTX *ctx) +{ + X509 *err_cert; + char buf[256]; + + err_cert=X509_STORE_CTX_get_current_cert(ctx); + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); + return ok; +} + +/* Return error string for last OpenSSL error + */ +static char *SSL_strerror(unsigned long error, char *buf, size_t size) +{ +#ifdef HAVE_ERR_ERROR_STRING_N + /* OpenSSL 0.9.6 and later has a function named + ERRO_error_string_n() that takes the size of the buffer as a + third argument */ + ERR_error_string_n(error, buf, size); +#else + (void) size; + ERR_error_string(error, buf); +#endif + return (buf); +} + +#endif /* USE_SSLEAY */ + +#ifdef USE_SSLEAY +/** + * Global SSL init + * + * @retval 0 error initializing SSL + * @retval 1 SSL initialized successfully + */ +int Curl_ossl_init(void) +{ +#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES + ENGINE_load_builtin_engines(); +#endif + + /* Lets get nice error messages */ + SSL_load_error_strings(); + + /* Setup all the global SSL stuff */ + if (!SSLeay_add_ssl_algorithms()) + return 0; + + return 1; +} + +#endif /* USE_SSLEAY */ + +#ifdef USE_SSLEAY + +/* Global cleanup */ +void Curl_ossl_cleanup(void) +{ + /* Free the SSL error strings */ + ERR_free_strings(); + + /* EVP_cleanup() removes all ciphers and digests from the + table. */ + EVP_cleanup(); + +#ifdef HAVE_ENGINE_cleanup + ENGINE_cleanup(); +#endif + +#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA + /* this function was not present in 0.9.6b, but was added sometimes + later */ + CRYPTO_cleanup_all_ex_data(); +#endif +} + +/* + * This function uses SSL_peek to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int Curl_ossl_check_cxn(struct connectdata *conn) +{ + int rc; + char buf; + + rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1); + if (rc > 0) + return 1; /* connection still in place */ + + if (rc == 0) + return 0; /* connection has been closed */ + + return -1; /* connection status unknown */ +} + +#endif /* USE_SSLEAY */ + +/* Selects an OpenSSL crypto engine + */ +CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) +{ +#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) + ENGINE *e = ENGINE_by_id(engine); + + if (!e) { + failf(data, "SSL Engine '%s' not found", engine); + return (CURLE_SSL_ENGINE_NOTFOUND); + } + + if (data->state.engine) { + ENGINE_finish(data->state.engine); + ENGINE_free(data->state.engine); + data->state.engine = NULL; + } + if (!ENGINE_init(e)) { + char buf[256]; + + ENGINE_free(e); + failf(data, "Failed to initialise SSL Engine '%s':\n%s", + engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf))); + return (CURLE_SSL_ENGINE_INITFAILED); + } + data->state.engine = e; + return (CURLE_OK); +#else + (void)engine; + failf(data, "SSL Engine not supported"); + return (CURLE_SSL_ENGINE_NOTFOUND); +#endif +} + +#ifdef USE_SSLEAY +/* Sets engine as default for all SSL operations + */ +CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) +{ +#ifdef HAVE_OPENSSL_ENGINE_H + if (data->state.engine) { + if (ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { + infof(data,"set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine)); + } + else { + failf(data, "set default crypto engine '%s' failed", ENGINE_get_id(data->state.engine)); + return CURLE_SSL_ENGINE_SETFAILED; + } + } +#else + (void) data; +#endif + return CURLE_OK; +} +#endif /* USE_SSLEAY */ + +/* Return list of OpenSSL crypto engine names. + */ +struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) +{ + struct curl_slist *list = NULL; +#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) + ENGINE *e; + + for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) + list = curl_slist_append(list, ENGINE_get_id(e)); +#endif + (void) data; + return (list); +} + + +#ifdef USE_SSLEAY + +/* + * This function is called when an SSL connection is closed. + */ +void Curl_ossl_close(struct connectdata *conn) +{ + int i; + /* + ERR_remove_state() frees the error queue associated with + thread pid. If pid == 0, the current thread will have its + error queue removed. + + Since error queue data structures are allocated + automatically for new threads, they must be freed when + threads are terminated in oder to avoid memory leaks. + */ + ERR_remove_state(0); + + for(i=0; i<2; i++) { + struct ssl_connect_data *connssl = &conn->ssl[i]; + + if(connssl->handle) { + (void)SSL_shutdown(connssl->handle); + SSL_set_connect_state(connssl->handle); + + SSL_free (connssl->handle); + connssl->handle = NULL; + } + if(connssl->ctx) { + SSL_CTX_free (connssl->ctx); + connssl->ctx = NULL; + } + connssl->use = FALSE; /* get back to ordinary socket usage */ + } +} + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) +{ + int retval = 0; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + char buf[120]; /* We will use this for the OpenSSL error buffer, so it has + to be at least 120 bytes long. */ + unsigned long sslerror; + ssize_t nread; + int err; + int done = 0; + + /* 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(connssl->handle) { + while(!done) { + int what = Curl_select(conn->sock[sockindex], + CURL_SOCKET_BAD, 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 */ + nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf, + sizeof(buf)); + err = SSL_get_error(conn->ssl[sockindex].handle, (int)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 = 1; + break; + case SSL_ERROR_WANT_READ: + /* there's data pending, re-invoke SSL_read() */ + infof(data, "SSL_ERROR_WANT_READ\n"); + break; + case SSL_ERROR_WANT_WRITE: + /* SSL wants a write. Really odd. Let's bail out. */ + infof(data, "SSL_ERROR_WANT_WRITE\n"); + done = 1; + break; + default: + /* openssl/ssl.h says "look at error stack/return value/errno" */ + sslerror = ERR_get_error(); + failf(conn->data, "SSL read: %s, errno %d", + ERR_error_string(sslerror, buf), + Curl_sockerrno() ); + done = 1; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = 1; + break; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + retval = -1; + done = 1; + } + } /* while()-loop for the select() */ + + if(data->set.verbose) { + switch(SSL_get_shutdown(connssl->handle)) { + case SSL_SENT_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); + break; + case SSL_RECEIVED_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); + break; + case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" + "SSL_RECEIVED__SHUTDOWN\n"); + break; + } + } + + connssl->use = FALSE; /* get back to ordinary socket usage */ + + SSL_free (connssl->handle); + connssl->handle = NULL; + } + return retval; +} + +void Curl_ossl_session_free(void *ptr) +{ + /* free the ID */ + SSL_SESSION_free(ptr); +} + +/* + * This function is called when the 'data' struct is going away. Close + * down everything and free all resources! + */ +int Curl_ossl_close_all(struct SessionHandle *data) +{ +#ifdef HAVE_OPENSSL_ENGINE_H + if(data->state.engine) { + ENGINE_finish(data->state.engine); + ENGINE_free(data->state.engine); + data->state.engine = NULL; + } +#else + (void)data; +#endif + return 0; +} + +static int Curl_ASN1_UTCTIME_output(struct connectdata *conn, + const char *prefix, + ASN1_UTCTIME *tm) +{ + char *asn1_string; + int gmt=FALSE; + int i; + int year=0,month=0,day=0,hour=0,minute=0,second=0; + struct SessionHandle *data = conn->data; + + if(!data->set.verbose) + return 0; + + i=tm->length; + asn1_string=(char *)tm->data; + + if(i < 10) + return 1; + if(asn1_string[i-1] == 'Z') + gmt=TRUE; + for (i=0; i<10; i++) + if((asn1_string[i] > '9') || (asn1_string[i] < '0')) + return 2; + + year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0'); + if(year < 50) + year+=100; + + month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0'); + if((month > 12) || (month < 1)) + return 3; + + day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0'); + hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0'); + minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0'); + + if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') && + (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) + second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0'); + + infof(data, + "%s%04d-%02d-%02d %02d:%02d:%02d %s\n", + prefix, year+1900, month, day, hour, minute, second, (gmt?"GMT":"")); + + return 0; +} + +#endif + +/* ====================================================== */ +#ifdef USE_SSLEAY + +/* + * Match a hostname against a wildcard pattern. + * E.g. + * "foo.host.com" matches "*.host.com". + * + * We are a bit more liberal than RFC2818 describes in that we + * accept multiple "*" in pattern (similar to what some other browsers do). + * E.g. + * "abc.def.domain.com" should strickly not match "*.domain.com", but we + * don't consider "." to be important in CERT checking. + */ +#define HOST_NOMATCH 0 +#define HOST_MATCH 1 + +static int hostmatch(const char *hostname, const char *pattern) +{ + while (1) { + int c = *pattern++; + + if (c == '\0') + return (*hostname ? HOST_NOMATCH : HOST_MATCH); + + if (c == '*') { + c = *pattern; + if (c == '\0') /* "*\0" matches anything remaining */ + return HOST_MATCH; + + while (*hostname) { + /* The only recursive function in libcurl! */ + if (hostmatch(hostname++,pattern) == HOST_MATCH) + return HOST_MATCH; + } + break; + } + + if (toupper(c) != toupper(*hostname++)) + break; + } + return HOST_NOMATCH; +} + +static int +cert_hostcheck(const char *match_pattern, const char *hostname) +{ + if (!match_pattern || !*match_pattern || + !hostname || !*hostname) /* sanity check */ + return 0; + + if(curl_strequal(hostname,match_pattern)) /* trivial case */ + return 1; + + if (hostmatch(hostname,match_pattern) == HOST_MATCH) + return 1; + return 0; +} + +/* Quote from RFC2818 section 3.1 "Server Identity" + + If a subjectAltName extension of type dNSName is present, that MUST + be used as the identity. Otherwise, the (most specific) Common Name + field in the Subject field of the certificate MUST be used. Although + the use of the Common Name is existing practice, it is deprecated and + 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 + 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 + component or component fragment. E.g., *.a.com matches foo.a.com but + not bar.foo.a.com. f*.com matches foo.com but not bar.com. + + In some cases, the URI is specified as an IP address rather than a + hostname. In this case, the iPAddress subjectAltName must be present + in the certificate and must exactly match the IP in the URI. + +*/ +static CURLcode verifyhost(struct connectdata *conn, + X509 *server_cert) +{ + bool matched = FALSE; /* no alternative match yet */ + int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ + int addrlen = 0; + struct SessionHandle *data = conn->data; + STACK_OF(GENERAL_NAME) *altnames; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + CURLcode res = CURLE_OK; + +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip && + Curl_inet_pton(AF_INET6, conn->host.name, &addr)) { + target = GEN_IPADD; + addrlen = sizeof(struct in6_addr); + } + else +#endif + if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) { + target = GEN_IPADD; + addrlen = sizeof(struct in_addr); + } + + /* get a "list" of alternative names */ + altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); + + if(altnames) { + int numalts; + int i; + + /* get amount of alternatives, RFC2459 claims there MUST be at least + one, but we don't depend on it... */ + numalts = sk_GENERAL_NAME_num(altnames); + + /* loop through all alternatives while none has matched */ + for (i=0; (itype == target) { + /* get data and length */ + const char *altptr = (char *)ASN1_STRING_data(check->d.ia5); + int altlen; + + switch(target) { + case GEN_DNS: /* name/pattern comparison */ + /* 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 + type itself: for example for and IA5String the data will be ASCII" + + Gisle researched the OpenSSL sources: + "I checked the 0.9.6 and 0.9.8 sources before my patch and + it always 0-terminates an IA5String." + */ + if (cert_hostcheck(altptr, conn->host.name)) + matched = TRUE; + break; + + case GEN_IPADD: /* IP address comparison */ + /* compare alternative IP address if the data chunk is the same size + our server IP address is */ + altlen = ASN1_STRING_length(check->d.ia5); + if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) + matched = TRUE; + break; + } + } + } + GENERAL_NAMES_free(altnames); + } + + if(matched) + /* an alternative name matched the server hostname */ + infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); + else { + /* we have to look to the last occurence of a commonName in the + distinguished one to get the most significant one. */ + int j,i=-1 ; + +/* The following is done because of a bug in 0.9.6b */ + + unsigned char *nulstr = (unsigned char *)""; + unsigned char *peer_CN = nulstr; + + X509_NAME *name = X509_get_subject_name(server_cert) ; + if (name) + while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0) + i=j; + + /* we have the name entry and we will now convert this to a string + that we can use for comparison. Doing this we support BMPstring, + UTF8 etc. */ + + if (i>=0) { + ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); + + /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input + is already UTF-8 encoded. We check for this case and copy the raw + string manually to avoid the problem. This code can be made + conditional in the future when OpenSSL has been fixed. Work-around + brought by Alexis S. L. Carvalho. */ + if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { + j = ASN1_STRING_length(tmp); + if (j >= 0) { + peer_CN = OPENSSL_malloc(j+1); + if (peer_CN) { + memcpy(peer_CN, ASN1_STRING_data(tmp), j); + peer_CN[j] = '\0'; + } + } + } + else /* not a UTF8 name */ + j = ASN1_STRING_to_UTF8(&peer_CN, tmp); + } + + if (peer_CN == nulstr) + peer_CN = NULL; +#ifdef CURL_DOES_CONVERSIONS + else { + /* convert peer_CN from UTF8 */ + size_t rc; + rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN)); + /* Curl_convert_from_utf8 calls failf if unsuccessful */ + if (rc != CURLE_OK) { + return(rc); + } + } +#endif /* CURL_DOES_CONVERSIONS */ + + if (!peer_CN) { + if(data->set.ssl.verifyhost > 1) { + failf(data, + "SSL: unable to obtain common name from peer certificate"); + return CURLE_SSL_PEER_CERTIFICATE; + } + else { + /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we + output a note about the situation */ + infof(data, "\t common name: WARNING couldn't obtain\n"); + } + } + else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) { + if(data->set.ssl.verifyhost > 1) { + failf(data, "SSL: certificate subject name '%s' does not match " + "target host name '%s'", peer_CN, conn->host.dispname); + res = CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "\t common name: %s (does not match '%s')\n", + peer_CN, conn->host.dispname); + } + else { + infof(data, "\t common name: %s (matched)\n", peer_CN); + } + if(peer_CN) + OPENSSL_free(peer_CN); + } + return res; +} +#endif + +/* 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 + +static const char *ssl_msg_type(int ssl_ver, int msg) +{ + if (ssl_ver == SSL2_VERSION_MAJOR) { + switch (msg) { + case SSL2_MT_ERROR: + return "Error"; + case SSL2_MT_CLIENT_HELLO: + return "Client hello"; + case SSL2_MT_CLIENT_MASTER_KEY: + return "Client key"; + case SSL2_MT_CLIENT_FINISHED: + return "Client finished"; + case SSL2_MT_SERVER_HELLO: + return "Server hello"; + case SSL2_MT_SERVER_VERIFY: + return "Server verify"; + case SSL2_MT_SERVER_FINISHED: + return "Server finished"; + case SSL2_MT_REQUEST_CERTIFICATE: + return "Request CERT"; + case SSL2_MT_CLIENT_CERTIFICATE: + return "Client CERT"; + } + } + else if (ssl_ver == SSL3_VERSION_MAJOR) { + switch (msg) { + case SSL3_MT_HELLO_REQUEST: + return "Hello request"; + case SSL3_MT_CLIENT_HELLO: + return "Client hello"; + case SSL3_MT_SERVER_HELLO: + return "Server hello"; + case SSL3_MT_CERTIFICATE: + return "CERT"; + case SSL3_MT_SERVER_KEY_EXCHANGE: + return "Server key exchange"; + case SSL3_MT_CLIENT_KEY_EXCHANGE: + return "Client key exchange"; + case SSL3_MT_CERTIFICATE_REQUEST: + return "Request CERT"; + case SSL3_MT_SERVER_DONE: + return "Server finished"; + case SSL3_MT_CERTIFICATE_VERIFY: + return "CERT verify"; + case SSL3_MT_FINISHED: + return "Finished"; + } + } + return "Unknown"; +} + +static const char *tls_rt_type(int type) +{ + return ( + type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " : + type == SSL3_RT_ALERT ? "TLS alert, " : + type == SSL3_RT_HANDSHAKE ? "TLS handshake, " : + type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " : + "TLS Unknown, "); +} + + +/* + * Our callback from the SSL/TLS layers. + */ +static void ssl_tls_trace(int direction, int ssl_ver, int content_type, + const void *buf, size_t len, const SSL *ssl, + struct connectdata *conn) +{ + struct SessionHandle *data; + const char *msg_name, *tls_rt_name; + char ssl_buf[1024]; + int ver, msg_type, txt_len; + + if (!conn || !conn->data || !conn->data->set.fdebug || + (direction != 0 && direction != 1)) + return; + + data = conn->data; + ssl_ver >>= 8; + ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' : + ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?'); + + /* 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]'. + */ + if (ssl_ver == SSL3_VERSION_MAJOR && content_type != 0) + tls_rt_name = tls_rt_type(content_type); + else + tls_rt_name = ""; + + msg_type = *(char*)buf; + msg_name = ssl_msg_type(ssl_ver, msg_type); + + txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n", + ver, tls_rt_name, msg_name, msg_type); + Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); + + Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : + CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL); + (void) ssl; +} +#endif + +#ifdef USE_SSLEAY +/* ====================================================== */ + +static CURLcode +Curl_ossl_connect_step1(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode = CURLE_OK; + + struct SessionHandle *data = conn->data; + SSL_METHOD_QUAL SSL_METHOD *req_method=NULL; + void *ssl_sessionid=NULL; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + curlassert(ssl_connect_1 == connssl->connecting_state); + + /* Make funny stuff to get random input */ + Curl_ossl_seed(data); + + /* check to see if we've been told to use an explicit SSL/TLS version */ + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + /* we try to figure out version */ + req_method = SSLv23_client_method(); + break; + case CURL_SSLVERSION_TLSv1: + req_method = TLSv1_client_method(); + break; + case CURL_SSLVERSION_SSLv2: +#ifdef OPENSSL_NO_SSL2 + failf(data, "OpenSSL was built without SSLv2 support"); + return CURLE_NOT_BUILT_IN; +#else + req_method = SSLv2_client_method(); + break; +#endif + case CURL_SSLVERSION_SSLv3: + req_method = SSLv3_client_method(); + break; + } + + if (connssl->ctx) + SSL_CTX_free(connssl->ctx); + connssl->ctx = SSL_CTX_new(req_method); + + if(!connssl->ctx) { + failf(data, "SSL: couldn't create a context!"); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef SSL_CTRL_SET_MSG_CALLBACK + if (data->set.fdebug && data->set.verbose) { + /* the SSL trace callback is only used for verbose logging so we only + inform about failures of setting it */ + if (!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK, + (void (*)(void))ssl_tls_trace)) { + infof(data, "SSL: couldn't set callback!\n"); + } + else if (!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, + conn)) { + infof(data, "SSL: couldn't set callback argument!\n"); + } + } +#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 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." + + */ + SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL); + +#if 0 + /* + * Not sure it's needed to tell SSL_connect() that socket is + * non-blocking. It doesn't seem to care, but just return with + * SSL_ERROR_WANT_x. + */ + if (data->state.used_interface == Curl_if_multi) + SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL); +#endif + + if(data->set.cert) { + if(!cert_stuff(conn, + connssl->ctx, + data->set.cert, + data->set.cert_type, + data->set.key, + data->set.key_type)) { + /* failf() is already done in cert_stuff() */ + return CURLE_SSL_CERTPROBLEM; + } + } + + if(data->set.ssl.cipher_list) { + if(!SSL_CTX_set_cipher_list(connssl->ctx, + data->set.ssl.cipher_list)) { + failf(data, "failed setting cipher list"); + return CURLE_SSL_CIPHER; + } + } + + if (data->set.ssl.CAfile || data->set.ssl.CApath) { + /* tell SSL where to find CA certificates that are used to verify + the servers certificate. */ + if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile, + data->set.ssl.CApath)) { + if (data->set.ssl.verifypeer) { + /* Fail if we insist on successfully verifying the server. */ + failf(data,"error setting certificate verify locations:\n" + " CAfile: %s\n CApath: %s\n", + data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", + data->set.ssl.CApath ? data->set.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:\n"); + } + } + else { + /* Everything is fine. */ + infof(data, "successfully set certificate verify locations:\n"); + } + infof(data, + " CAfile: %s\n" + " CApath: %s\n", + data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", + data->set.ssl.CApath ? data->set.ssl.CApath : "none"); + } + /* SSL 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(connssl->ctx, + data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, + cert_verify_callback); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx, + data->set.ssl.fsslctxp); + if(retcode) { + failf(data,"error signaled by ssl ctx callback"); + return retcode; + } + } + + /* Lets make an SSL structure */ + if (connssl->handle) + SSL_free(connssl->handle); + connssl->handle = SSL_new(connssl->ctx); + if (!connssl->handle) { + failf(data, "SSL: couldn't create a context (handle)!"); + return CURLE_OUT_OF_MEMORY; + } + SSL_set_connect_state(connssl->handle); + + connssl->server_cert = 0x0; + + /* Check if there's a cached ID we can/should use here! */ + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if (!SSL_set_session(connssl->handle, ssl_sessionid)) { + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(ERR_get_error(),NULL)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + + /* pass the raw socket into the SSL layers */ + if (!SSL_set_fd(connssl->handle, sockfd)) { + failf(data, "SSL: SSL_set_fd failed: %s", + ERR_error_string(ERR_get_error(),NULL)); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; +} + +static CURLcode +Curl_ossl_connect_step2(struct connectdata *conn, + int sockindex, long *timeout_ms) +{ + struct SessionHandle *data = conn->data; + int err; + long has_passed; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + curlassert(ssl_connect_2 == connssl->connecting_state + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state); + + /* Find out if any timeout is set. If not, use 300 seconds. + Otherwise, figure out the most strict timeout of the two possible one + and then how much time that has elapsed to know how much time we + allow for the connect call */ + if(data->set.timeout && data->set.connecttimeout) { + /* get the most strict timeout of the ones converted to milliseconds */ + if(data->set.timeoutset.connecttimeout) + *timeout_ms = data->set.timeout*1000; + else + *timeout_ms = data->set.connecttimeout*1000; + } + else if(data->set.timeout) + *timeout_ms = data->set.timeout*1000; + else if(data->set.connecttimeout) + *timeout_ms = data->set.connecttimeout*1000; + else + /* no particular time-out has been set */ + *timeout_ms= DEFAULT_CONNECT_TIMEOUT; + + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + + /* subtract the passed time */ + *timeout_ms -= has_passed; + + if(*timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEOUTED; + } + + err = SSL_connect(connssl->handle); + + /* 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(connssl->handle, err); + + if(SSL_ERROR_WANT_READ == detail) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + else if(SSL_ERROR_WANT_WRITE == detail) { + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } + else { + /* untreated error */ + unsigned long errdetail; + char error_buffer[256]; /* OpenSSL documents that this must be at least + 256 bytes long. */ + CURLcode rc; + const char *cert_problem = NULL; + + connssl->connecting_state = ssl_connect_2; /* the connection failed, + we're not waiting for + anything else. */ + + errdetail = ERR_get_error(); /* Gets the earliest error code from the + thread's error queue and removes the + entry. */ + + switch(errdetail) { + case 0x1407E086: + /* 1407E086: + SSL routines: + SSL2_SET_CERTIFICATE: + certificate verify failed */ + /* fall-through */ + case 0x14090086: + /* 14090086: + SSL routines: + SSL3_GET_SERVER_CERTIFICATE: + certificate verify failed */ + cert_problem = "SSL certificate problem, verify that the CA cert is" + " OK. Details:\n"; + rc = CURLE_SSL_CACERT; + break; + default: + rc = CURLE_SSL_CONNECT_ERROR; + break; + } + + /* detail is already set to the SSL error above */ + + /* 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. + */ + if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) { + failf(data, "Unknown SSL protocol error in connection to %s:%d ", + conn->host.name, conn->port); + return rc; + } + /* Could be a CERT problem */ + + SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); + failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); + return rc; + } + } + else { + /* we have been connected fine, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_3; + + /* Informational message */ + infof (data, "SSL connection using %s\n", + SSL_get_cipher(connssl->handle)); + + return CURLE_OK; + } +} + +static CURLcode +Curl_ossl_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode = CURLE_OK; + char * str; + long lerr; + ASN1_TIME *certdate; + void *ssl_sessionid=NULL; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + curlassert(ssl_connect_3 == connssl->connecting_state); + + if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* Since this is not a cached session ID, then we want to stach this one + in the cache! */ + SSL_SESSION *our_ssl_sessionid; +#ifdef HAVE_SSL_GET1_SESSION + our_ssl_sessionid = SSL_get1_session(connssl->handle); + + /* SSL_get1_session() will increment the reference + count and the session will stay in memory until explicitly freed with + SSL_SESSION_free(3), regardless of its state. + This function was introduced in openssl 0.9.5a. */ +#else + our_ssl_sessionid = SSL_get_session(connssl->handle); + + /* if SSL_get1_session() is unavailable, use SSL_get_session(). + This is an inferior option because the session can be flushed + at any time by openssl. It is included only so curl compiles + under versions of openssl < 0.9.5a. + + WARNING: How curl behaves if it's session is flushed is + untested. + */ +#endif + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(retcode) { + failf(data, "failed to store ssl session"); + return retcode; + } + } + + + /* Get server's certificate (note: beware of dynamic allocation) - opt */ + /* major serious hack alert -- we should check certificates + * to authenticate the server; otherwise we risk man-in-the-middle + * attack + */ + + connssl->server_cert = SSL_get_peer_certificate(connssl->handle); + if(!connssl->server_cert) { + failf(data, "SSL: couldn't get peer certificate!"); + return CURLE_SSL_PEER_CERTIFICATE; + } + infof (data, "Server certificate:\n"); + + str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert), + NULL, 0); + if(!str) { + failf(data, "SSL: couldn't get X509-subject!"); + X509_free(connssl->server_cert); + connssl->server_cert = NULL; + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "\t subject: %s\n", str); + CRYPTO_free(str); + + certdate = X509_get_notBefore(connssl->server_cert); + Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); + + certdate = X509_get_notAfter(connssl->server_cert); + Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); + + if(data->set.ssl.verifyhost) { + retcode = verifyhost(conn, connssl->server_cert); + if(retcode) { + X509_free(connssl->server_cert); + connssl->server_cert = NULL; + return retcode; + } + } + + str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert), + NULL, 0); + if(!str) { + failf(data, "SSL: couldn't get X509-issuer name!"); + retcode = CURLE_SSL_CONNECT_ERROR; + } + else { + infof(data, "\t issuer: %s\n", str); + CRYPTO_free(str); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + lerr = data->set.ssl.certverifyresult= + SSL_get_verify_result(connssl->handle); + if(data->set.ssl.certverifyresult != X509_V_OK) { + if(data->set.ssl.verifypeer) { + /* We probably never reach this, because SSL_connect() will fail + and we return earlyer if verifypeer is set? */ + failf(data, "SSL certificate verify result: %s (%ld)", + X509_verify_cert_error_string(lerr), lerr); + retcode = CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "SSL certificate verify result: %s (%ld)," + " continuing anyway.\n", + X509_verify_cert_error_string(lerr), lerr); + } + else + infof(data, "SSL certificate verify ok.\n"); + } + + X509_free(connssl->server_cert); + connssl->server_cert = NULL; + connssl->connecting_state = ssl_connect_done; + return retcode; +} + +static CURLcode +Curl_ossl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode retcode; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + + if (ssl_connect_1==connssl->connecting_state) { + retcode = Curl_ossl_connect_step1(conn, sockindex); + if (retcode) + return retcode; + } + + timeout_ms = 0; + while (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* 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 writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + int readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + while(1) { + int what = Curl_select(readfd, writefd, nonblocking?0:(int)timeout_ms); + if(what > 0) + /* readable or writable, go loop in the outer loop */ + break; + else if(0 == what) { + if (nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + return CURLE_SSL_CONNECT_ERROR; + } + } /* while()-loop for the select() */ + } + + /* get the timeout from step2 to avoid computing it twice. */ + retcode = Curl_ossl_connect_step2(conn, sockindex, &timeout_ms); + if (retcode) + return retcode; + + } /* repeat step2 until all transactions are done. */ + + + if (ssl_connect_3==connssl->connecting_state) { + retcode = Curl_ossl_connect_step3(conn, sockindex); + if (retcode) + return retcode; + } + + if (ssl_connect_done==connssl->connecting_state) { + *done = TRUE; + } + else { + *done = FALSE; + } + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode +Curl_ossl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return Curl_ossl_connect_common(conn, sockindex, TRUE, done); +} + +CURLcode +Curl_ossl_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode; + bool done = FALSE; + + retcode = Curl_ossl_connect_common(conn, sockindex, FALSE, &done); + if (retcode) + return retcode; + + curlassert(done); + + return CURLE_OK; +} + +/* return number of sent (non-SSL) bytes */ +ssize_t Curl_ossl_send(struct connectdata *conn, + int sockindex, + void *mem, + size_t len) +{ + /* SSL_write() is said to return 'int' while write() and send() returns + 'size_t' */ + int err; + char error_buffer[120]; /* OpenSSL documents that this must be at least 120 + bytes long. */ + unsigned long sslerror; + int rc = SSL_write(conn->ssl[sockindex].handle, mem, (int)len); + + if(rc < 0) { + err = SSL_get_error(conn->ssl[sockindex].handle, rc); + + switch(err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* The operation did not complete; the same TLS/SSL I/O function + should be called again later. This is basicly an EWOULDBLOCK + equivalent. */ + return 0; + case SSL_ERROR_SYSCALL: + failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n", + Curl_sockerrno()); + return -1; + case SSL_ERROR_SSL: + /* A failure in the SSL library occurred, usually a protocol error. + The OpenSSL error queue contains more information on the error. */ + sslerror = ERR_get_error(); + failf(conn->data, "SSL_write() error: %s\n", + ERR_error_string(sslerror, error_buffer)); + return -1; + } + /* a true error */ + failf(conn->data, "SSL_write() return error %d\n", err); + return -1; + } + return (ssize_t)rc; /* number of bytes */ +} + +/* + * If the read would block we return -1 and set 'wouldblock' to TRUE. + * Otherwise we return the amount of data read. Other errors should return -1 + * and set 'wouldblock' to FALSE. + */ +ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + bool *wouldblock) +{ + char error_buffer[120]; /* OpenSSL documents that this must be at + least 120 bytes long. */ + unsigned long sslerror; + ssize_t nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, + (int)buffersize); + *wouldblock = FALSE; + if(nread < 0) { + /* failed SSL_read */ + int err = SSL_get_error(conn->ssl[num].handle, (int)nread); + + switch(err) { + case SSL_ERROR_NONE: /* this is not an error */ + case SSL_ERROR_ZERO_RETURN: /* no more data */ + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* there's data pending, re-invoke SSL_read() */ + *wouldblock = TRUE; + return -1; /* basically EWOULDBLOCK */ + default: + /* openssl/ssl.h says "look at error stack/return value/errno" */ + sslerror = ERR_get_error(); + failf(conn->data, "SSL read: %s, errno %d", + ERR_error_string(sslerror, error_buffer), + Curl_sockerrno() ); + return -1; + } + } + return nread; +} + +size_t Curl_ossl_version(char *buffer, size_t size) +{ +#ifdef YASSL_VERSION + /* yassl provides an OpenSSL API compatiblity layer so it looks identical + to OpenSSL in all other aspects */ + return snprintf(buffer, size, " yassl/%s", YASSL_VERSION); +#else /* YASSL_VERSION */ + +#if (SSLEAY_VERSION_NUMBER >= 0x905000) + { + char sub[2]; + unsigned long ssleay_value; + sub[1]='\0'; + ssleay_value=SSLeay(); + if(ssleay_value < 0x906000) { + ssleay_value=SSLEAY_VERSION_NUMBER; + sub[0]='\0'; + } + else { + if(ssleay_value&0xff0) { + sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); + } + else + sub[0]='\0'; + } + + return snprintf(buffer, size, " OpenSSL/%lx.%lx.%lx%s", + (ssleay_value>>28)&0xf, + (ssleay_value>>20)&0xff, + (ssleay_value>>12)&0xff, + sub); + } + +#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ + +#if (SSLEAY_VERSION_NUMBER >= 0x900000) + return snprintf(buffer, size, " OpenSSL/%lx.%lx.%lx", + (SSLEAY_VERSION_NUMBER>>28)&0xff, + (SSLEAY_VERSION_NUMBER>>20)&0xff, + (SSLEAY_VERSION_NUMBER>>12)&0xf); + +#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ + { + char sub[2]; + sub[1]='\0'; + if(SSLEAY_VERSION_NUMBER&0x0f) { + sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1; + } + else + sub[0]='\0'; + + return snprintf(buffer, size, " SSL/%x.%x.%x%s", + (SSLEAY_VERSION_NUMBER>>12)&0xff, + (SSLEAY_VERSION_NUMBER>>8)&0xf, + (SSLEAY_VERSION_NUMBER>>4)&0xf, sub); + } +#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ +#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ + +#endif /* YASSL_VERSION */ +} +#endif /* USE_SSLEAY */ diff --git a/Utilities/cmcurl/lib/ssluse.h b/Utilities/cmcurl/lib/ssluse.h new file mode 100644 index 0000000..5bb7090 --- /dev/null +++ b/Utilities/cmcurl/lib/ssluse.h @@ -0,0 +1,71 @@ +#ifndef __SSLUSE_H +#define __SSLUSE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * This header should only be needed to get included by sslgen.c and ssluse.c + */ + +#include "urldata.h" +CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); +CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); +void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */ +/* tell OpenSSL to close down all open information regarding connections (and + thus session ID caching etc) */ +int Curl_ossl_close_all(struct SessionHandle *data); +/* Sets an OpenSSL engine */ +CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine); + +/* function provided for the generic SSL-layer, called when a session id + should be freed */ +void Curl_ossl_session_free(void *ptr); + +/* Sets engine as default for all SSL operations */ +CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data); + +/* Build list of OpenSSL engines */ +struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data); + +int Curl_ossl_init(void); +void Curl_ossl_cleanup(void); + +ssize_t Curl_ossl_send(struct connectdata *conn, + int sockindex, + void *mem, + size_t len); +ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + bool *wouldblock); + +size_t Curl_ossl_version(char *buffer, size_t size); +int Curl_ossl_check_cxn(struct connectdata *cxn); +int Curl_ossl_seed(struct SessionHandle *data); + +int Curl_ossl_shutdown(struct connectdata *conn, int sockindex); + +#endif diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c new file mode 100644 index 0000000..e16e08a --- /dev/null +++ b/Utilities/cmcurl/lib/strdup.c @@ -0,0 +1,46 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include "strdup.h" + +#ifndef HAVE_STRDUP +char *curlx_strdup(const char *str) +{ + int len; + char *newstr; + + if (!str) + return (char *)NULL; + + len = strlen(str); + newstr = (char *) malloc((len+1)*sizeof(char)); + if (!newstr) + return (char *)NULL; + + strcpy(newstr,str); + + return newstr; + +} +#endif diff --git a/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h new file mode 100644 index 0000000..3206db3 --- /dev/null +++ b/Utilities/cmcurl/lib/strdup.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifndef _CURL_STRDUP_H +#define _CURL_STRDUP_H + +#include "setup.h" + +#ifndef HAVE_STRDUP +extern char *curlx_strdup(const char *str); +#endif + +#endif + diff --git a/Utilities/cmcurl/lib/strequal.c b/Utilities/cmcurl/lib/strequal.c new file mode 100644 index 0000000..83796f6 --- /dev/null +++ b/Utilities/cmcurl/lib/strequal.c @@ -0,0 +1,101 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +#include "strequal.h" + +#if defined(HAVE_STRCASECMP) && defined(__STRICT_ANSI__) +/* this is for "-ansi -Wall -pedantic" to stop complaining! */ +extern int (strcasecmp)(const char *s1, const char *s2); +extern int (strncasecmp)(const char *s1, const char *s2, size_t n); +#endif + +int curl_strequal(const char *first, const char *second) +{ +#if defined(HAVE_STRCASECMP) + return !(strcasecmp)(first, second); +#elif defined(HAVE_STRCMPI) + return !(strcmpi)(first, second); +#elif defined(HAVE_STRICMP) + return !(stricmp)(first, second); +#else + while (*first && *second) { + if (toupper(*first) != toupper(*second)) { + break; + } + first++; + second++; + } + return toupper(*first) == toupper(*second); +#endif +} + +int curl_strnequal(const char *first, const char *second, size_t max) +{ +#if defined(HAVE_STRCASECMP) + return !strncasecmp(first, second, max); +#elif defined(HAVE_STRCMPI) + return !strncmpi(first, second, max); +#elif defined(HAVE_STRICMP) + return !strnicmp(first, second, max); +#else + while (*first && *second && max) { + if (toupper(*first) != toupper(*second)) { + break; + } + max--; + first++; + second++; + } + if(0 == max) + return 1; /* they are equal this far */ + + return toupper(*first) == toupper(*second); +#endif +} + +/* + * Curl_strcasestr() finds the first occurrence of the substring needle in the + * string haystack. The terminating `\0' characters are not compared. The + * matching is done CASE INSENSITIVE, which thus is the difference between + * this and strstr(). + */ +char *Curl_strcasestr(const char *haystack, const char *needle) +{ + size_t nlen = strlen(needle); + size_t hlen = strlen(haystack); + + while(hlen-- >= nlen) { + if(curl_strnequal(haystack, needle, nlen)) + return (char *)haystack; + haystack++; + } + return NULL; +} diff --git a/Utilities/cmcurl/lib/strequal.h b/Utilities/cmcurl/lib/strequal.h new file mode 100644 index 0000000..6718c3c0 --- /dev/null +++ b/Utilities/cmcurl/lib/strequal.h @@ -0,0 +1,38 @@ +#ifndef __STREQUAL_H +#define __STREQUAL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include + +#define strequal(a,b) curl_strequal(a,b) +#define strnequal(a,b,c) curl_strnequal(a,b,c) + +/* checkprefix() is a shorter version of the above, used when the first + argument is zero-byte terminated */ +#define checkprefix(a,b) strnequal(a,b,strlen(a)) + +/* case insensitive strstr() */ +char *Curl_strcasestr(const char *haystack, const char *needle); + +#endif diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c new file mode 100644 index 0000000..74c3457 --- /dev/null +++ b/Utilities/cmcurl/lib/strerror.c @@ -0,0 +1,751 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2004 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_STRERROR_R +#if !defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R) +#error "you MUST have either POSIX or glibc strerror_r if strerror_r is found" +#endif /* !POSIX && !glibc */ +#endif /* HAVE_STRERROR_R */ + +#include +#include +#include +#include + +#ifdef USE_LIBIDN +#include +#endif + +#include "strerror.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#if defined(HAVE_STRERROR_R) && defined(HAVE_NO_STRERROR_R_DECL) +#ifdef HAVE_POSIX_STRERROR_R +/* seen on AIX 5100-02 gcc 2.9 */ +extern int strerror_r(int errnum, char *strerrbuf, size_t buflen); +#else +extern char *strerror_r(int errnum, char *buf, size_t buflen); +#endif +#endif + +const char * +curl_easy_strerror(CURLcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch (error) { + case CURLE_OK: + return "no error"; + + case CURLE_UNSUPPORTED_PROTOCOL: + return "unsupported protocol"; + + case CURLE_FAILED_INIT: + return "failed init"; + + case CURLE_URL_MALFORMAT: + return "URL using bad/illegal format or missing URL"; + + case CURLE_NOT_BUILT_IN: + return "A requested feature, protocol or option was not found built-in in" + " this libcurl due to a build-time decision."; + + case CURLE_COULDNT_RESOLVE_PROXY: + return "couldn't resolve proxy name"; + + case CURLE_COULDNT_RESOLVE_HOST: + return "couldn't resolve host name"; + + case CURLE_COULDNT_CONNECT: + return "couldn't connect to server"; + + case CURLE_FTP_WEIRD_SERVER_REPLY: + return "FTP: weird server reply"; + + case CURLE_FTP_ACCESS_DENIED: + return "FTP: access denied"; + + case CURLE_FTP_WEIRD_PASS_REPLY: + return "FTP: unknown PASS reply"; + + case CURLE_FTP_WEIRD_USER_REPLY: + return "FTP: unknown USER reply"; + + case CURLE_FTP_WEIRD_PASV_REPLY: + return "FTP: unknown PASV reply"; + + case CURLE_FTP_WEIRD_227_FORMAT: + return "FTP: unknown 227 response format"; + + case CURLE_FTP_CANT_GET_HOST: + return "FTP: can't figure out the host in the PASV response"; + + case CURLE_FTP_CANT_RECONNECT: + return "FTP: can't connect to server the response code is unknown"; + + case CURLE_FTP_COULDNT_SET_BINARY: + return "FTP: couldn't set binary mode"; + + case CURLE_PARTIAL_FILE: + return "Transferred a partial file"; + + case CURLE_FTP_COULDNT_RETR_FILE: + return "FTP: couldn't retrieve (RETR failed) the specified file"; + + case CURLE_FTP_WRITE_ERROR: + return "FTP: the post-transfer acknowledge response was not OK"; + + case CURLE_FTP_QUOTE_ERROR: + return "FTP: a quote command returned error"; + + case CURLE_HTTP_RETURNED_ERROR: + return "HTTP response code said error"; + + case CURLE_WRITE_ERROR: + return "failed writing received data to disk/application"; + + case CURLE_FTP_COULDNT_STOR_FILE: + return "failed FTP upload (the STOR command)"; + + case CURLE_READ_ERROR: + return "failed to open/read local data from file/application"; + + case CURLE_OUT_OF_MEMORY: +#ifdef CURL_DOES_CONVERSIONS + return "conversion failed -or- out of memory"; +#else + return "out of memory"; +#endif /* CURL_DOES_CONVERSIONS */ + + case CURLE_OPERATION_TIMEOUTED: + return "a timeout was reached"; + + case CURLE_FTP_COULDNT_SET_ASCII: + return "FTP could not set ASCII mode (TYPE A)"; + + case CURLE_FTP_PORT_FAILED: + return "FTP command PORT failed"; + + case CURLE_FTP_COULDNT_USE_REST: + return "FTP command REST failed"; + + case CURLE_FTP_COULDNT_GET_SIZE: + return "FTP command SIZE failed"; + + case CURLE_HTTP_RANGE_ERROR: + return "a range was requested but the server did not deliver it"; + + case CURLE_HTTP_POST_ERROR: + return "internal problem setting up the POST"; + + case CURLE_SSL_CONNECT_ERROR: + return "SSL connect error"; + + case CURLE_BAD_DOWNLOAD_RESUME: + return "couldn't resume download"; + + case CURLE_FILE_COULDNT_READ_FILE: + return "couldn't read a file:// file"; + + case CURLE_LDAP_CANNOT_BIND: + return "LDAP: cannot bind"; + + case CURLE_LDAP_SEARCH_FAILED: + return "LDAP: search failed"; + + case CURLE_LIBRARY_NOT_FOUND: + return "a required shared library was not found"; + + case CURLE_FUNCTION_NOT_FOUND: + return "a required function in the shared library was not found"; + + case CURLE_ABORTED_BY_CALLBACK: + return "the operation was aborted by an application callback"; + + case CURLE_BAD_FUNCTION_ARGUMENT: + return "a libcurl function was given a bad argument"; + + case CURLE_INTERFACE_FAILED: + return "failed binding local connection end"; + + case CURLE_TOO_MANY_REDIRECTS : + return "number of redirects hit maximum amount"; + + case CURLE_UNKNOWN_TELNET_OPTION: + return "User specified an unknown option"; + + case CURLE_TELNET_OPTION_SYNTAX : + return "Malformed telnet option"; + + case CURLE_SSL_PEER_CERTIFICATE: + return "SSL peer certificate was not ok"; + + case CURLE_GOT_NOTHING: + return "server returned nothing (no headers, no data)"; + + case CURLE_SSL_ENGINE_NOTFOUND: + return "SSL crypto engine not found"; + + case CURLE_SSL_ENGINE_SETFAILED: + return "can not set SSL crypto engine as default"; + + case CURLE_SSL_ENGINE_INITFAILED: + return "failed to initialise SSL crypto engine"; + + case CURLE_SEND_ERROR: + return "failed sending data to the peer"; + + case CURLE_RECV_ERROR: + return "failure when receiving data from the peer"; + + case CURLE_SHARE_IN_USE: + return "share is already in use"; + + case CURLE_SSL_CERTPROBLEM: + return "problem with the local SSL certificate"; + + case CURLE_SSL_CIPHER: + return "couldn't use specified SSL cipher"; + + case CURLE_SSL_CACERT: + return "peer certificate cannot be authenticated with known CA certificates"; + + case CURLE_SSL_CACERT_BADFILE: + return "problem with the SSL CA cert (path? access rights?)"; + + case CURLE_BAD_CONTENT_ENCODING: + return "Unrecognized HTTP Content-Encoding"; + + case CURLE_LDAP_INVALID_URL: + return "Invalid LDAP URL"; + + case CURLE_FILESIZE_EXCEEDED: + return "Maximum file size exceeded"; + + case CURLE_FTP_SSL_FAILED: + return "Requested FTP SSL level failed"; + + case CURLE_SSL_SHUTDOWN_FAILED: + return "Failed to shut down the SSL connection"; + + case CURLE_SEND_FAIL_REWIND: + return "Send failed since rewinding of the data stream failed"; + + case CURLE_LOGIN_DENIED: + return "FTP: login denied"; + + case CURLE_TFTP_NOTFOUND: + return "TFTP: File Not Found"; + + case CURLE_TFTP_PERM: + return "TFTP: Access Violation"; + + case CURLE_TFTP_DISKFULL: + return "TFTP: Disk full or allocation exceeded"; + + case CURLE_TFTP_ILLEGAL: + return "TFTP: Illegal operation"; + + case CURLE_TFTP_UNKNOWNID: + return "TFTP: Unknown transfer ID"; + + case CURLE_TFTP_EXISTS: + return "TFTP: File already exists"; + + case CURLE_TFTP_NOSUCHUSER: + return "TFTP: No such user"; + + case CURLE_CONV_FAILED: + return "conversion failed"; + + case CURLE_CONV_REQD: + return "caller must register CURLOPT_CONV_ callback options"; + + case CURLE_REMOTE_FILE_NOT_FOUND: + return "Remote file not found"; + + case CURLE_SSH: + return "Error in the SSH layer"; + + /* error codes not used by current libcurl */ + case CURLE_FTP_USER_PASSWORD_INCORRECT: + case CURLE_MALFORMAT_USER: + case CURLE_BAD_CALLING_ORDER: + case CURLE_BAD_PASSWORD_ENTERED: + case CURLE_OBSOLETE: + case CURL_LAST: + break; + } + /* + * 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 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. 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. + */ + return "unknown error"; +#else + if (error == CURLE_OK) + return "no error"; + else + return "error"; +#endif +} + +const char * +curl_multi_strerror(CURLMcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch (error) { + case CURLM_CALL_MULTI_PERFORM: + return "please call curl_multi_perform() soon"; + + case CURLM_OK: + return "no error"; + + case CURLM_BAD_HANDLE: + return "invalid multi handle"; + + case CURLM_BAD_EASY_HANDLE: + return "invalid easy handle"; + + case CURLM_OUT_OF_MEMORY: + return "out of memory"; + + case CURLM_INTERNAL_ERROR: + return "internal error"; + + case CURLM_BAD_SOCKET: + return "invalid socket argument"; + + case CURLM_UNKNOWN_OPTION: + return "unknown option"; + + case CURLM_LAST: + break; + } + + return "unknown error"; +#else + if (error == CURLM_OK) + return "no error"; + else + return "error"; +#endif +} + +const char * +curl_share_strerror(CURLSHcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch (error) { + case CURLSHE_OK: + return "no error"; + + case CURLSHE_BAD_OPTION: + return "unknown share option"; + + case CURLSHE_IN_USE: + return "share currently in use"; + + case CURLSHE_INVALID: + return "invalid share handle"; + + case CURLSHE_NOMEM: + return "out of memory"; + + case CURLSHE_LAST: + break; + } + + return "CURLSH unknown"; +#else + if (error == CURLSHE_OK) + return "no error"; + else + return "error"; +#endif +} + +#ifdef USE_WINSOCK + +/* This function handles most / all (?) Winsock errors cURL is able to produce. + */ +static const char * +get_winsock_error (int err, char *buf, size_t len) +{ + const char *p; + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch (err) { + case WSAEINTR: + p = "Call interrupted."; + break; + case WSAEBADF: + p = "Bad file"; + break; + case WSAEACCES: + p = "Bad access"; + break; + case WSAEFAULT: + p = "Bad argument"; + break; + case WSAEINVAL: + p = "Invalid arguments"; + break; + case WSAEMFILE: + p = "Out of file descriptors"; + break; + case WSAEWOULDBLOCK: + p = "Call would block"; + break; + case WSAEINPROGRESS: + case WSAEALREADY: + p = "Blocking call in progress"; + break; + case WSAENOTSOCK: + p = "Descriptor is not a socket."; + break; + case WSAEDESTADDRREQ: + p = "Need destination address"; + break; + case WSAEMSGSIZE: + p = "Bad message size"; + break; + case WSAEPROTOTYPE: + p = "Bad protocol"; + break; + case WSAENOPROTOOPT: + p = "Protocol option is unsupported"; + break; + case WSAEPROTONOSUPPORT: + p = "Protocol is unsupported"; + break; + case WSAESOCKTNOSUPPORT: + p = "Socket is unsupported"; + break; + case WSAEOPNOTSUPP: + p = "Operation not supported"; + break; + case WSAEAFNOSUPPORT: + p = "Address family not supported"; + break; + case WSAEPFNOSUPPORT: + p = "Protocol family not supported"; + break; + case WSAEADDRINUSE: + p = "Address already in use"; + break; + case WSAEADDRNOTAVAIL: + p = "Address not available"; + break; + case WSAENETDOWN: + p = "Network down"; + break; + case WSAENETUNREACH: + p = "Network unreachable"; + break; + case WSAENETRESET: + p = "Network has been reset"; + break; + case WSAECONNABORTED: + p = "Connection was aborted"; + break; + case WSAECONNRESET: + p = "Connection was reset"; + break; + case WSAENOBUFS: + p = "No buffer space"; + break; + case WSAEISCONN: + p = "Socket is already connected"; + break; + case WSAENOTCONN: + p = "Socket is not connected"; + break; + case WSAESHUTDOWN: + p = "Socket has been shut down"; + break; + case WSAETOOMANYREFS: + p = "Too many references"; + break; + case WSAETIMEDOUT: + p = "Timed out"; + break; + case WSAECONNREFUSED: + p = "Connection refused"; + break; + case WSAELOOP: + p = "Loop??"; + break; + case WSAENAMETOOLONG: + p = "Name too long"; + break; + case WSAEHOSTDOWN: + p = "Host down"; + break; + case WSAEHOSTUNREACH: + p = "Host unreachable"; + break; + case WSAENOTEMPTY: + p = "Not empty"; + break; + case WSAEPROCLIM: + p = "Process limit reached"; + break; + case WSAEUSERS: + p = "Too many users"; + break; + case WSAEDQUOT: + p = "Bad quota"; + break; + case WSAESTALE: + p = "Something is stale"; + break; + case WSAEREMOTE: + p = "Remote error"; + break; +#ifdef WSAEDISCON /* missing in SalfordC! */ + case WSAEDISCON: + p = "Disconnected"; + break; +#endif + /* Extended Winsock errors */ + case WSASYSNOTREADY: + p = "Winsock library is not ready"; + break; + case WSANOTINITIALISED: + p = "Winsock library not initialised"; + break; + case WSAVERNOTSUPPORTED: + p = "Winsock version not supported."; + break; + + /* getXbyY() errors (already handled in herrmsg): + * Authoritative Answer: Host not found */ + case WSAHOST_NOT_FOUND: + p = "Host not found"; + break; + + /* Non-Authoritative: Host not found, or SERVERFAIL */ + case WSATRY_AGAIN: + p = "Host not found, try again"; + break; + + /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ + case WSANO_RECOVERY: + p = "Unrecoverable error in call to nameserver"; + break; + + /* Valid name, no data record of requested type */ + case WSANO_DATA: + p = "No data record of requested type"; + break; + + default: + return NULL; + } +#else + if (error == CURLE_OK) + return NULL; + else + p = "error"; +#endif + strncpy (buf, p, len); + buf [len-1] = '\0'; + return buf; +} +#endif /* USE_WINSOCK */ + +/* + * Our thread-safe and smart strerror() replacement. + * + * 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" convertion function and there might + * be systems that don't do proper range checking in there themselves. + * + * We don't do range checking (on systems other than Windows) since there is + * no good reliable and portable way to do it. + */ +const char *Curl_strerror(struct connectdata *conn, int err) +{ + char *buf, *p; + size_t max; + + curlassert(conn); + curlassert(err >= 0); + + buf = conn->syserr_buf; + max = sizeof(conn->syserr_buf)-1; + *buf = '\0'; + +#ifdef USE_WINSOCK + +#ifdef _WIN32_WCE + buf[0]=0; + { + wchar_t wbuf[256]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL); + wcstombs(buf,wbuf,max); + } + +#else + + /* 'sys_nerr' is the maximum errno number, it is not widely portable */ + if (err >= 0 && err < sys_nerr) + strncpy(buf, strerror(err), max); + else { + if (!get_winsock_error(err, buf, max) && + !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + LANG_NEUTRAL, buf, (DWORD)max, NULL)) + snprintf(buf, max, "Unknown error %d (%#x)", err, err); + } +#endif +#else /* not USE_WINSOCK coming up */ + + /* These should be atomic and hopefully thread-safe */ +#ifdef HAVE_STRERROR_R + /* There are two different APIs for strerror_r(). The POSIX and the GLIBC + versions. */ +#ifdef HAVE_POSIX_STRERROR_R + strerror_r(err, buf, max); + /* this may set errno to ERANGE if insufficient storage was supplied via + 'strerrbuf' and 'buflen' to contain the generated message string, or + EINVAL if the value of 'errnum' is not a valid error number.*/ +#else + { + /* HAVE_GLIBC_STRERROR_R */ + char buffer[256]; + char *msg = strerror_r(err, buffer, sizeof(buffer)); + /* this version of strerror_r() only *might* use the buffer we pass to + the function, but it always returns the error message as a pointer, + so we must copy that string unconditionally (if non-NULL) */ + if(msg) + strncpy(buf, msg, max); + else + snprintf(buf, max, "Unknown error %d", err); + } +#endif /* end of HAVE_GLIBC_STRERROR_R */ +#else /* HAVE_STRERROR_R */ + strncpy(buf, strerror(err), max); +#endif /* end of HAVE_STRERROR_R */ +#endif /* end of ! USE_WINSOCK */ + + buf[max] = '\0'; /* make sure the string is zero terminated */ + + /* strip trailing '\r\n' or '\n'. */ + if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2) + *p = '\0'; + if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1) + *p = '\0'; + return buf; +} + +#ifdef USE_LIBIDN +/* + * Return error-string for libidn status as returned from idna_to_ascii_lz(). + */ +const char *Curl_idn_strerror (struct connectdata *conn, int err) +{ +#ifdef HAVE_IDNA_STRERROR + (void)conn; + return idna_strerror((Idna_rc) err); +#else + const char *str; + char *buf; + size_t max; + + curlassert(conn); + + buf = conn->syserr_buf; + max = sizeof(conn->syserr_buf)-1; + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch ((Idna_rc)err) { + case IDNA_SUCCESS: + str = "No error"; + break; + case IDNA_STRINGPREP_ERROR: + str = "Error in string preparation"; + break; + case IDNA_PUNYCODE_ERROR: + str = "Error in Punycode operation"; + break; + case IDNA_CONTAINS_NON_LDH: + str = "Illegal ASCII characters"; + break; + case IDNA_CONTAINS_MINUS: + str = "Contains minus"; + break; + case IDNA_INVALID_LENGTH: + str = "Invalid output length"; + break; + case IDNA_NO_ACE_PREFIX: + str = "No ACE prefix (\"xn--\")"; + break; + case IDNA_ROUNDTRIP_VERIFY_ERROR: + str = "Roundtrip verify error"; + break; + case IDNA_CONTAINS_ACE_PREFIX: + str = "Already have ACE prefix (\"xn--\")"; + break; + case IDNA_ICONV_ERROR: + str = "Locale conversion failed"; + break; + case IDNA_MALLOC_ERROR: + str = "Allocation failed"; + break; + case IDNA_DLOPEN_ERROR: + str = "dlopen() error"; + break; + default: + snprintf(buf, max, "error %d", (int)err); + str = NULL; + break; + } +#else + if ((Idna_rc)err == IDNA_SUCCESS) + str = "No error"; + else + str = "error"; +#endif + if (str) + strncpy(buf, str, max); + buf[max] = '\0'; + return (buf); +#endif +} +#endif /* USE_LIBIDN */ diff --git a/Utilities/cmcurl/lib/strerror.h b/Utilities/cmcurl/lib/strerror.h new file mode 100644 index 0000000..b280504 --- /dev/null +++ b/Utilities/cmcurl/lib/strerror.h @@ -0,0 +1,34 @@ +#ifndef __CURL_STRERROR_H +#define __CURL_STRERROR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "urldata.h" + +const char *Curl_strerror (struct connectdata *conn, int err); + +#ifdef USE_LIBIDN +const char *Curl_idn_strerror (struct connectdata *conn, int err); +#endif + +#endif diff --git a/Utilities/cmcurl/lib/strtok.c b/Utilities/cmcurl/lib/strtok.c new file mode 100644 index 0000000..630e4e0 --- /dev/null +++ b/Utilities/cmcurl/lib/strtok.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef HAVE_STRTOK_R +#include +#include + +#include "strtok.h" + +char * +Curl_strtok_r(char *ptr, const char *sep, char **end) +{ + if (!ptr) + /* we got NULL input so then we get our last position instead */ + ptr = *end; + + /* pass all letters that are including in the separator string */ + while (*ptr && strchr(sep, *ptr)) + ++ptr; + + if (*ptr) { + /* so this is where the next piece of string starts */ + char *start = ptr; + + /* set the end pointer to the first byte after the start */ + *end = start + 1; + + /* scan through the string to find where it ends, it ends on a + null byte or a character that exists in the separator string */ + while (**end && !strchr(sep, **end)) + ++*end; + + if (**end) { + /* the end is not a null byte */ + **end = '\0'; /* zero terminate it! */ + ++*end; /* advance the last pointer to beyond the null byte */ + } + + return start; /* return the position where the string starts */ + } + + /* we ended up on a null byte, there are no more strings to find! */ + return NULL; +} + +#endif /* this was only compiled if strtok_r wasn't present */ diff --git a/Utilities/cmcurl/lib/strtok.h b/Utilities/cmcurl/lib/strtok.h new file mode 100644 index 0000000..cf9fac8 --- /dev/null +++ b/Utilities/cmcurl/lib/strtok.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#ifndef _CURL_STRTOK_R_H +#define _CURL_STRTOK_R_H + +#include "setup.h" +#include + +#ifndef HAVE_STRTOK_R +char *Curl_strtok_r(char *s, const char *delim, char **last); +#define strtok_r Curl_strtok_r +#else +#include +#endif + +#endif + diff --git a/Utilities/cmcurl/lib/strtoofft.c b/Utilities/cmcurl/lib/strtoofft.c new file mode 100644 index 0000000..3ab1bfd --- /dev/null +++ b/Utilities/cmcurl/lib/strtoofft.c @@ -0,0 +1,165 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" +#include "strtoofft.h" + +/* + * NOTE: + * + * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we + * could use in case strtoll() doesn't exist... See + * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html + */ + +#ifdef NEED_CURL_STRTOLL +#include +#include +#include + +static int get_char(char c, int base); + +/** + * Emulated version of the strtoll function. This extracts a long long + * value from the given input string and returns it. + */ +curl_off_t +curlx_strtoll(const char *nptr, char **endptr, int base) +{ + char *end; + int is_negative = 0; + int overflow; + int i; + curl_off_t value = 0; + curl_off_t newval; + + /* Skip leading whitespace. */ + end = (char *)nptr; + while (ISSPACE(end[0])) { + end++; + } + + /* Handle the sign, if any. */ + if (end[0] == '-') { + is_negative = 1; + end++; + } + else if (end[0] == '+') { + end++; + } + else if (end[0] == '\0') { + /* We had nothing but perhaps some whitespace -- there was no number. */ + if (endptr) { + *endptr = end; + } + return 0; + } + + /* Handle special beginnings, if present and allowed. */ + if (end[0] == '0' && end[1] == 'x') { + if (base == 16 || base == 0) { + end += 2; + base = 16; + } + } + else if (end[0] == '0') { + if (base == 8 || base == 0) { + end++; + base = 8; + } + } + + /* 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)) { + newval = base * value + i; + if (newval < value) { + /* We've overflowed. */ + overflow = 1; + break; + } + else + value = newval; + } + + if (!overflow) { + if (is_negative) { + /* Fix the sign. */ + value *= -1; + } + } + else { + if (is_negative) + value = CURL_LLONG_MIN; + else + value = CURL_LLONG_MAX; + + errno = ERANGE; + } + + if (endptr) + *endptr = end; + + return value; +} + +/** + * Returns the value of c in the given base, or -1 if c cannot + * be interpreted properly in that base (i.e., is out of range, + * is a null, etc.). + * + * @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 isn't in range + */ +static int get_char(char c, int base) +{ + int value = -1; + if (c <= '9' && c >= '0') { + value = c - '0'; + } + else if (c <= 'Z' && c >= 'A') { + value = c - 'A' + 10; + } + else if (c <= 'z' && c >= 'a') { + value = c - 'a' + 10; + } + + if (value >= base) { + value = -1; + } + + return value; +} +#endif /* Only present if we need strtoll, but don't have it. */ diff --git a/Utilities/cmcurl/lib/strtoofft.h b/Utilities/cmcurl/lib/strtoofft.h new file mode 100644 index 0000000..e27b432 --- /dev/null +++ b/Utilities/cmcurl/lib/strtoofft.h @@ -0,0 +1,73 @@ +#ifndef _CURL_STRTOOFFT_H +#define _CURL_STRTOOFFT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * CAUTION: this header is designed to work when included by the app-side + * as well as the library. Do not mix with library internals! + */ + +#include "setup.h" +#include +#include /* for the curl_off_t type */ + +/* Determine what type of file offset conversion handling we wish to use. For + * systems with a 32-bit curl_off_t type, we should use strtol. For systems + * with a 64-bit curl_off_t type, we should use strtoll if it exists, and if + * not, should try to emulate its functionality. At any rate, we define + * 'strtoofft' such that it can be used to work with curl_off_t's regardless. + */ +#if (SIZEOF_CURL_OFF_T > 4) && (SIZEOF_LONG < 8) +#if HAVE_STRTOLL +#define curlx_strtoofft strtoll +#else /* HAVE_STRTOLL */ + +/* For MSVC7 we can use _strtoi64() which seems to be a strtoll() clone */ +#if defined(_MSC_VER) && (_MSC_VER >= 1300) +#define curlx_strtoofft _strtoi64 +#else /* MSVC7 or later */ +curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base); +#define curlx_strtoofft curlx_strtoll +#define NEED_CURL_STRTOLL +#endif /* MSVC7 or later */ + +#endif /* HAVE_STRTOLL */ +#else /* (SIZEOF_CURL_OFF_T > 4) && (SIZEOF_LONG < 8) */ +/* simply use strtol() to get numbers, either 32 or 64 bit */ +#define curlx_strtoofft strtol +#endif + +#if defined(_MSC_VER) || defined(__WATCOMC__) +#define CURL_LLONG_MIN 0x8000000000000000i64 +#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFi64 +#elif defined(HAVE_LL) +#define CURL_LLONG_MIN 0x8000000000000000LL +#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFLL +#else +#define CURL_LLONG_MIN 0x8000000000000000L +#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFL +#endif + +#endif + diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c new file mode 100644 index 0000000..97d22b7 --- /dev/null +++ b/Utilities/cmcurl/lib/telnet.c @@ -0,0 +1,1403 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_TELNET +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#if defined(WIN32) +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + + +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "telnet.h" +#include "connect.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#define TELOPTS +#define TELCMDS + +#include "arpa_telnet.h" +#include "memory.h" +#include "select.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#define SUBBUFSIZE 512 + +#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer; +#define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); } +#define CURL_SB_ACCUM(x,c) \ + if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \ + *x->subpointer++ = (c); \ + } + +#define CURL_SB_GET(x) ((*x->subpointer++)&0xff) +#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) +#define CURL_SB_EOF(x) (x->subpointer >= x->subend) +#define CURL_SB_LEN(x) (x->subend - x->subpointer) + +#ifdef USE_WINSOCK +typedef FARPROC WSOCK2_FUNC; +static CURLcode check_wsock2 ( struct SessionHandle *data ); +#endif + +static +void telrcv(struct connectdata *, + unsigned char *inbuf, /* Data received from socket */ + ssize_t count); /* Number of bytes received */ + +static void printoption(struct SessionHandle *data, + const char *direction, + int cmd, int option); + +static void negotiate(struct connectdata *); +static void send_negotiation(struct connectdata *, int cmd, int option); +static void set_local_option(struct connectdata *, int cmd, int option); +static void set_remote_option(struct connectdata *, int cmd, int option); + +static void printsub(struct SessionHandle *data, + int direction, unsigned char *pointer, + size_t length); +static void suboption(struct connectdata *); + +/* For negotiation compliant to RFC 1143 */ +#define CURL_NO 0 +#define CURL_YES 1 +#define CURL_WANTYES 2 +#define CURL_WANTNO 3 + +#define CURL_EMPTY 0 +#define CURL_OPPOSITE 1 + +/* + * Telnet receiver states for fsm + */ +typedef enum +{ + CURL_TS_DATA = 0, + CURL_TS_IAC, + CURL_TS_WILL, + CURL_TS_WONT, + CURL_TS_DO, + CURL_TS_DONT, + CURL_TS_CR, + CURL_TS_SB, /* sub-option collection */ + CURL_TS_SE /* looking for sub-option end */ +} TelnetReceive; + +struct TELNET { + int please_negotiate; + int already_negotiated; + int us[256]; + int usq[256]; + int us_preferred[256]; + int him[256]; + int himq[256]; + int him_preferred[256]; + char subopt_ttype[32]; /* Set with suboption TTYPE */ + char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ + struct curl_slist *telnet_vars; /* Environment variables */ + + /* suboptions */ + unsigned char subbuffer[SUBBUFSIZE]; + unsigned char *subpointer, *subend; /* buffer for sub-options */ + + TelnetReceive telrcv_state; +}; + +#ifdef USE_WINSOCK +static CURLcode +check_wsock2 ( struct SessionHandle *data ) +{ + int err; + WORD wVersionRequested; + WSADATA wsaData; + + curlassert(data); + + /* telnet requires at least WinSock 2.0 so ask for it. */ + wVersionRequested = MAKEWORD(2, 0); + + err = WSAStartup(wVersionRequested, &wsaData); + + /* We must've called this once already, so this call */ + /* should always succeed. But, just in case... */ + if (err != 0) { + failf(data,"WSAStartup failed (%d)",err); + return CURLE_FAILED_INIT; + } + + /* We have to have a WSACleanup call for every successful */ + /* WSAStartup call. */ + WSACleanup(); + + /* Check that our version is supported */ + if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || + HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) { + /* Our version isn't supported */ + failf(data,"insufficient winsock version to support " + "telnet"); + return CURLE_FAILED_INIT; + } + + /* Our version is supported */ + return CURLE_OK; +} +#endif + +static +CURLcode init_telnet(struct connectdata *conn) +{ + struct TELNET *tn; + + tn = (struct TELNET *)calloc(1, sizeof(struct TELNET)); + if(!tn) + return CURLE_OUT_OF_MEMORY; + + conn->data->reqdata.proto.telnet = (void *)tn; /* make us known */ + + tn->telrcv_state = CURL_TS_DATA; + + /* Init suboptions */ + CURL_SB_CLEAR(tn); + + /* Set the options we want by default */ + tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; + tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; + tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; + tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; + + return CURLE_OK; +} + +static void negotiate(struct connectdata *conn) +{ + int i; + struct TELNET *tn = (struct TELNET *) conn->data->reqdata.proto.telnet; + + for(i = 0;i < CURL_NTELOPTS;i++) + { + if(tn->us_preferred[i] == CURL_YES) + set_local_option(conn, i, CURL_YES); + + if(tn->him_preferred[i] == CURL_YES) + set_remote_option(conn, i, CURL_YES); + } +} + +static void printoption(struct SessionHandle *data, + const char *direction, int cmd, int option) +{ + const char *fmt; + const char *opt; + + if (data->set.verbose) + { + if (cmd == CURL_IAC) + { + if (CURL_TELCMD_OK(option)) + infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option)); + else + infof(data, "%s IAC %d\n", direction, option); + } + else + { + fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" : + (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0; + if (fmt) + { + if (CURL_TELOPT_OK(option)) + opt = CURL_TELOPT(option); + else if (option == CURL_TELOPT_EXOPL) + opt = "EXOPL"; + else + opt = NULL; + + if(opt) + infof(data, "%s %s %s\n", direction, fmt, opt); + else + infof(data, "%s %s %d\n", direction, fmt, option); + } + else + infof(data, "%s %d %d\n", direction, cmd, option); + } + } +} + +static void send_negotiation(struct connectdata *conn, int cmd, int option) +{ + unsigned char buf[3]; + ssize_t bytes_written; + int err; + struct SessionHandle *data = conn->data; + + buf[0] = CURL_IAC; + buf[1] = (unsigned char)cmd; + buf[2] = (unsigned char)option; + + bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); + if(bytes_written < 0) { + err = Curl_sockerrno(); + failf(data,"Sending data failed (%d)",err); + } + + printoption(conn->data, "SENT", cmd, option); +} + +static +void set_remote_option(struct connectdata *conn, int option, int newstate) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + if(newstate == CURL_YES) + { + switch(tn->him[option]) + { + case CURL_NO: + tn->him[option] = CURL_WANTYES; + send_negotiation(conn, CURL_DO, option); + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->himq[option]) + { + case CURL_EMPTY: + /* Already negotiating for CURL_YES, queue the request */ + tn->himq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) + { + case CURL_EMPTY: + /* Error: already negotiating for enable */ + break; + case CURL_OPPOSITE: + tn->himq[option] = CURL_EMPTY; + break; + } + break; + } + } + else /* NO */ + { + switch(tn->him[option]) + { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->him[option] = CURL_WANTNO; + send_negotiation(conn, CURL_DONT, option); + break; + + case CURL_WANTNO: + switch(tn->himq[option]) + { + case CURL_EMPTY: + /* Already negotiating for NO */ + break; + case CURL_OPPOSITE: + tn->himq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) + { + case CURL_EMPTY: + tn->himq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + break; + } + break; + } + } +} + +static +void rec_will(struct connectdata *conn, int option) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + switch(tn->him[option]) + { + case CURL_NO: + if(tn->him_preferred[option] == CURL_YES) + { + tn->him[option] = CURL_YES; + send_negotiation(conn, CURL_DO, option); + } + else + { + send_negotiation(conn, CURL_DONT, option); + } + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->himq[option]) + { + case CURL_EMPTY: + /* Error: DONT answered by WILL */ + tn->him[option] = CURL_NO; + break; + case CURL_OPPOSITE: + /* Error: DONT answered by WILL */ + tn->him[option] = CURL_YES; + tn->himq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) + { + case CURL_EMPTY: + tn->him[option] = CURL_YES; + break; + case CURL_OPPOSITE: + tn->him[option] = CURL_WANTNO; + tn->himq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_DONT, option); + break; + } + break; + } +} + +static +void rec_wont(struct connectdata *conn, int option) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + switch(tn->him[option]) + { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->him[option] = CURL_NO; + send_negotiation(conn, CURL_DONT, option); + break; + + case CURL_WANTNO: + switch(tn->himq[option]) + { + case CURL_EMPTY: + tn->him[option] = CURL_NO; + break; + + case CURL_OPPOSITE: + tn->him[option] = CURL_WANTYES; + tn->himq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_DO, option); + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) + { + case CURL_EMPTY: + tn->him[option] = CURL_NO; + break; + case CURL_OPPOSITE: + tn->him[option] = CURL_NO; + tn->himq[option] = CURL_EMPTY; + break; + } + break; + } +} + +static void +set_local_option(struct connectdata *conn, int option, int newstate) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + if(newstate == CURL_YES) + { + switch(tn->us[option]) + { + case CURL_NO: + tn->us[option] = CURL_WANTYES; + send_negotiation(conn, CURL_WILL, option); + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->usq[option]) + { + case CURL_EMPTY: + /* Already negotiating for CURL_YES, queue the request */ + tn->usq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) + { + case CURL_EMPTY: + /* Error: already negotiating for enable */ + break; + case CURL_OPPOSITE: + tn->usq[option] = CURL_EMPTY; + break; + } + break; + } + } + else /* NO */ + { + switch(tn->us[option]) + { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->us[option] = CURL_WANTNO; + send_negotiation(conn, CURL_WONT, option); + break; + + case CURL_WANTNO: + switch(tn->usq[option]) + { + case CURL_EMPTY: + /* Already negotiating for NO */ + break; + case CURL_OPPOSITE: + tn->usq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) + { + case CURL_EMPTY: + tn->usq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + break; + } + break; + } + } +} + +static +void rec_do(struct connectdata *conn, int option) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + switch(tn->us[option]) + { + case CURL_NO: + if(tn->us_preferred[option] == CURL_YES) + { + tn->us[option] = CURL_YES; + send_negotiation(conn, CURL_WILL, option); + } + else + { + send_negotiation(conn, CURL_WONT, option); + } + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->usq[option]) + { + case CURL_EMPTY: + /* Error: DONT answered by WILL */ + tn->us[option] = CURL_NO; + break; + case CURL_OPPOSITE: + /* Error: DONT answered by WILL */ + tn->us[option] = CURL_YES; + tn->usq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) + { + case CURL_EMPTY: + tn->us[option] = CURL_YES; + break; + case CURL_OPPOSITE: + tn->us[option] = CURL_WANTNO; + tn->himq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_WONT, option); + break; + } + break; + } +} + +static +void rec_dont(struct connectdata *conn, int option) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + switch(tn->us[option]) + { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->us[option] = CURL_NO; + send_negotiation(conn, CURL_WONT, option); + break; + + case CURL_WANTNO: + switch(tn->usq[option]) + { + case CURL_EMPTY: + tn->us[option] = CURL_NO; + break; + + case CURL_OPPOSITE: + tn->us[option] = CURL_WANTYES; + tn->usq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_WILL, option); + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) + { + case CURL_EMPTY: + tn->us[option] = CURL_NO; + break; + case CURL_OPPOSITE: + tn->us[option] = CURL_NO; + tn->usq[option] = CURL_EMPTY; + break; + } + break; + } +} + + +static void printsub(struct SessionHandle *data, + int direction, /* '<' or '>' */ + unsigned char *pointer, /* where suboption data is */ + size_t length) /* length of suboption data */ +{ + unsigned int i = 0; + + if (data->set.verbose) + { + if (direction) + { + infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); + if (length >= 3) + { + int j; + + i = pointer[length-2]; + j = pointer[length-1]; + + if (i != CURL_IAC || j != CURL_SE) + { + infof(data, "(terminated by "); + if (CURL_TELOPT_OK(i)) + infof(data, "%s ", CURL_TELOPT(i)); + else if (CURL_TELCMD_OK(i)) + infof(data, "%s ", CURL_TELCMD(i)); + else + infof(data, "%d ", i); + if (CURL_TELOPT_OK(j)) + infof(data, "%s", CURL_TELOPT(j)); + else if (CURL_TELCMD_OK(j)) + infof(data, "%s", CURL_TELCMD(j)); + else + infof(data, "%d", j); + infof(data, ", not IAC SE!) "); + } + } + length -= 2; + } + if (length < 1) + { + infof(data, "(Empty suboption?)"); + return; + } + + if (CURL_TELOPT_OK(pointer[0])) { + switch(pointer[0]) { + case CURL_TELOPT_TTYPE: + case CURL_TELOPT_XDISPLOC: + case CURL_TELOPT_NEW_ENVIRON: + infof(data, "%s", CURL_TELOPT(pointer[0])); + break; + default: + infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); + break; + } + } + else + infof(data, "%d (unknown)", pointer[i]); + + switch(pointer[1]) { + case CURL_TELQUAL_IS: + infof(data, " IS"); + break; + case CURL_TELQUAL_SEND: + infof(data, " SEND"); + break; + case CURL_TELQUAL_INFO: + infof(data, " INFO/REPLY"); + break; + case CURL_TELQUAL_NAME: + infof(data, " NAME"); + break; + } + + switch(pointer[0]) { + case CURL_TELOPT_TTYPE: + case CURL_TELOPT_XDISPLOC: + pointer[length] = 0; + infof(data, " \"%s\"", &pointer[2]); + break; + case CURL_TELOPT_NEW_ENVIRON: + if(pointer[1] == CURL_TELQUAL_IS) { + infof(data, " "); + for(i = 3;i < length;i++) { + switch(pointer[i]) { + case CURL_NEW_ENV_VAR: + infof(data, ", "); + break; + case CURL_NEW_ENV_VALUE: + infof(data, " = "); + break; + default: + infof(data, "%c", pointer[i]); + break; + } + } + } + break; + default: + for (i = 2; i < length; i++) + infof(data, " %.2x", pointer[i]); + break; + } + + if (direction) + { + infof(data, "\n"); + } + } +} + +static CURLcode check_telnet_options(struct connectdata *conn) +{ + struct curl_slist *head; + char option_keyword[128]; + char option_arg[256]; + char *buf; + struct SessionHandle *data = conn->data; + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + + /* Add the user name as an environment variable if it + was given on the command line */ + if(conn->bits.user_passwd) + { + snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); + tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg); + + tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; + } + + for(head = data->set.telnet_options; head; head=head->next) { + if(sscanf(head->data, "%127[^= ]%*[ =]%255s", + option_keyword, option_arg) == 2) { + + /* Terminal type */ + if(curl_strequal(option_keyword, "TTYPE")) { + strncpy(tn->subopt_ttype, option_arg, 31); + tn->subopt_ttype[31] = 0; /* String termination */ + tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; + continue; + } + + /* Display variable */ + if(curl_strequal(option_keyword, "XDISPLOC")) { + strncpy(tn->subopt_xdisploc, option_arg, 127); + tn->subopt_xdisploc[127] = 0; /* String termination */ + tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; + continue; + } + + /* Environment variable */ + if(curl_strequal(option_keyword, "NEW_ENV")) { + buf = strdup(option_arg); + if(!buf) + return CURLE_OUT_OF_MEMORY; + tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf); + tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; + continue; + } + + failf(data, "Unknown telnet option %s", head->data); + return CURLE_UNKNOWN_TELNET_OPTION; + } else { + failf(data, "Syntax error in telnet option: %s", head->data); + return CURLE_TELNET_OPTION_SYNTAX; + } + } + + return CURLE_OK; +} + +/* + * suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + */ + +static void suboption(struct connectdata *conn) +{ + struct curl_slist *v; + unsigned char temp[2048]; + ssize_t bytes_written; + size_t len; + size_t tmplen; + int err; + char varname[128]; + char varval[128]; + struct SessionHandle *data = conn->data; + struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; + + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2); + switch (CURL_SB_GET(tn)) { + case CURL_TELOPT_TTYPE: + len = strlen(tn->subopt_ttype) + 4 + 2; + snprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = Curl_sockerrno(); + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_XDISPLOC: + len = strlen(tn->subopt_xdisploc) + 4 + 2; + snprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = Curl_sockerrno(); + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_NEW_ENVIRON: + snprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); + len = 4; + + for(v = tn->telnet_vars;v;v = v->next) { + tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { + sscanf(v->data, "%127[^,],%127s", varname, varval); + snprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); + len += tmplen; + } + } + snprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); + len += 2; + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = Curl_sockerrno(); + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + } + return; +} + +static +void telrcv(struct connectdata *conn, + unsigned char *inbuf, /* Data received from socket */ + ssize_t count) /* Number of bytes received */ +{ + unsigned char c; + int in = 0; + struct SessionHandle *data = conn->data; + struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; + + while(count--) + { + c = inbuf[in++]; + + switch (tn->telrcv_state) + { + case CURL_TS_CR: + tn->telrcv_state = CURL_TS_DATA; + if (c == '\0') + { + break; /* Ignore \0 after CR */ + } + + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); + continue; + + case CURL_TS_DATA: + if (c == CURL_IAC) + { + tn->telrcv_state = CURL_TS_IAC; + break; + } + else if(c == '\r') + { + tn->telrcv_state = CURL_TS_CR; + } + + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); + continue; + + case CURL_TS_IAC: + process_iac: + switch (c) + { + case CURL_WILL: + tn->telrcv_state = CURL_TS_WILL; + continue; + case CURL_WONT: + tn->telrcv_state = CURL_TS_WONT; + continue; + case CURL_DO: + tn->telrcv_state = CURL_TS_DO; + continue; + case CURL_DONT: + tn->telrcv_state = CURL_TS_DONT; + continue; + case CURL_SB: + CURL_SB_CLEAR(tn); + tn->telrcv_state = CURL_TS_SB; + continue; + case CURL_IAC: + Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); + break; + case CURL_DM: + case CURL_NOP: + case CURL_GA: + default: + printoption(data, "RCVD", CURL_IAC, c); + break; + } + tn->telrcv_state = CURL_TS_DATA; + continue; + + case CURL_TS_WILL: + printoption(data, "RCVD", CURL_WILL, c); + tn->please_negotiate = 1; + rec_will(conn, c); + tn->telrcv_state = CURL_TS_DATA; + continue; + + case CURL_TS_WONT: + printoption(data, "RCVD", CURL_WONT, c); + tn->please_negotiate = 1; + rec_wont(conn, c); + tn->telrcv_state = CURL_TS_DATA; + continue; + + case CURL_TS_DO: + printoption(data, "RCVD", CURL_DO, c); + tn->please_negotiate = 1; + rec_do(conn, c); + tn->telrcv_state = CURL_TS_DATA; + continue; + + case CURL_TS_DONT: + printoption(data, "RCVD", CURL_DONT, c); + tn->please_negotiate = 1; + rec_dont(conn, c); + tn->telrcv_state = CURL_TS_DATA; + continue; + + case CURL_TS_SB: + if (c == CURL_IAC) + { + tn->telrcv_state = CURL_TS_SE; + } + else + { + CURL_SB_ACCUM(tn,c); + } + continue; + + case CURL_TS_SE: + 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 happend. 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 + * not doubled, and really the IAC SE was left off, we could get + * into an infinate loop here. So, instead, we terminate the + * suboption, and process the partial suboption if we can. + */ + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, c); + tn->subpointer -= 2; + CURL_SB_TERM(tn); + + printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); + suboption(conn); /* handle sub-option */ + tn->telrcv_state = CURL_TS_IAC; + goto process_iac; + } + CURL_SB_ACCUM(tn,c); + tn->telrcv_state = CURL_TS_SB; + } + else + { + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, CURL_SE); + tn->subpointer -= 2; + CURL_SB_TERM(tn); + suboption(conn); /* handle sub-option */ + tn->telrcv_state = CURL_TS_DATA; + } + break; + } + } +} + +CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premature) +{ + struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; + (void)status; /* unused */ + (void)premature; /* not used */ + + curl_slist_free_all(tn->telnet_vars); + + free(conn->data->reqdata.proto.telnet); + conn->data->reqdata.proto.telnet = NULL; + + return CURLE_OK; +} + +CURLcode Curl_telnet(struct connectdata *conn, bool *done) +{ + CURLcode code; + struct SessionHandle *data = conn->data; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; +#ifdef USE_WINSOCK + HMODULE wsock2; + WSOCK2_FUNC close_event_func; + WSOCK2_FUNC create_event_func; + WSOCK2_FUNC event_select_func; + WSOCK2_FUNC enum_netevents_func; + WSAEVENT event_handle; + WSANETWORKEVENTS events; + HANDLE stdin_handle; + HANDLE objs[2]; + DWORD obj_count; + DWORD wait_timeout; + DWORD waitret; + DWORD readfile_read; +#else + int interval_ms; + struct pollfd pfd[2]; +#endif + ssize_t nread; + bool keepon = TRUE; + char *buf = data->state.buffer; + struct TELNET *tn; + + *done = TRUE; /* uncontionally */ + + code = init_telnet(conn); + if(code) + return code; + + tn = (struct TELNET *)data->reqdata.proto.telnet; + + code = check_telnet_options(conn); + if(code) + return code; + +#ifdef USE_WINSOCK + /* + ** This functionality only works with WinSock >= 2.0. So, + ** make sure have it. + */ + code = check_wsock2(data); + if (code) + return code; + + /* OK, so we have WinSock 2.0. We need to dynamically */ + /* load ws2_32.dll and get the function pointers we need. */ + wsock2 = LoadLibrary("WS2_32.DLL"); + if (wsock2 == NULL) { + failf(data,"failed to load WS2_32.DLL (%d)",GetLastError()); + return CURLE_FAILED_INIT; + } + + /* Grab a pointer to WSACreateEvent */ + create_event_func = GetProcAddress(wsock2,"WSACreateEvent"); + if (create_event_func == NULL) { + failf(data,"failed to find WSACreateEvent function (%d)", + GetLastError()); + FreeLibrary(wsock2); + return CURLE_FAILED_INIT; + } + + /* And WSACloseEvent */ + close_event_func = GetProcAddress(wsock2,"WSACloseEvent"); + if (close_event_func == NULL) { + failf(data,"failed to find WSACloseEvent function (%d)", + GetLastError()); + FreeLibrary(wsock2); + return CURLE_FAILED_INIT; + } + + /* And WSAEventSelect */ + event_select_func = GetProcAddress(wsock2,"WSAEventSelect"); + if (event_select_func == NULL) { + failf(data,"failed to find WSAEventSelect function (%d)", + GetLastError()); + FreeLibrary(wsock2); + return CURLE_FAILED_INIT; + } + + /* And WSAEnumNetworkEvents */ + enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents"); + if (enum_netevents_func == NULL) { + failf(data,"failed to find WSAEnumNetworkEvents function (%d)", + GetLastError()); + FreeLibrary(wsock2); + return CURLE_FAILED_INIT; + } + + /* We want to wait for both stdin and the socket. Since + ** the select() function in winsock only works on sockets + ** we have to use the WaitForMultipleObjects() call. + */ + + /* First, create a sockets event object */ + event_handle = (WSAEVENT)create_event_func(); + if (event_handle == WSA_INVALID_EVENT) { + failf(data,"WSACreateEvent failed (%d)",WSAGetLastError()); + FreeLibrary(wsock2); + return CURLE_FAILED_INIT; + } + + /* The get the Windows file handle for stdin */ + stdin_handle = GetStdHandle(STD_INPUT_HANDLE); + + /* Create the list of objects to wait for */ + objs[0] = event_handle; + objs[1] = stdin_handle; + + /* Tell winsock what events we want to listen to */ + if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { + close_event_func(event_handle); + FreeLibrary(wsock2); + return 0; + } + + /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, + else use the old WaitForMultipleObjects() way */ + if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) { + /* Don't wait for stdin_handle, just wait for event_handle */ + obj_count = 1; + /* Check stdin_handle per 100 milliseconds */ + wait_timeout = 100; + } else { + obj_count = 2; + wait_timeout = INFINITE; + } + + /* Keep on listening and act on events */ + while(keepon) { + waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); + switch(waitret) { + case WAIT_TIMEOUT: + { + unsigned char outbuf[2]; + int out_count = 0; + ssize_t bytes_written; + char *buffer = buf; + + while(1) { + if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { + keepon = FALSE; + break; + } + nread = readfile_read; + + if(!nread) + break; + + if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + &readfile_read, NULL)) { + keepon = FALSE; + break; + } + nread = readfile_read; + + while(nread--) { + outbuf[0] = *buffer++; + out_count = 1; + if(outbuf[0] == CURL_IAC) + outbuf[out_count++] = CURL_IAC; + + Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, + out_count, &bytes_written); + } + } + } + break; + + case WAIT_OBJECT_0 + 1: + { + unsigned char outbuf[2]; + int out_count = 0; + ssize_t bytes_written; + char *buffer = buf; + + if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + &readfile_read, NULL)) { + keepon = FALSE; + break; + } + nread = readfile_read; + + while(nread--) { + outbuf[0] = *buffer++; + out_count = 1; + if(outbuf[0] == CURL_IAC) + outbuf[out_count++] = CURL_IAC; + + Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, + out_count, &bytes_written); + } + } + break; + + case WAIT_OBJECT_0: + if(enum_netevents_func(sockfd, event_handle, &events) + != SOCKET_ERROR) { + if(events.lNetworkEvents & FD_READ) { + /* This reallu OUGHT to check its return code. */ + (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); + + telrcv(conn, (unsigned char *)buf, nread); + + fflush(stdout); + + /* Negotiate if the peer has started negotiating, + 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(conn); + tn->already_negotiated = 1; + } + } + + if(events.lNetworkEvents & FD_CLOSE) { + keepon = FALSE; + } + } + break; + } + } + + /* We called WSACreateEvent, so call WSACloseEvent */ + if (close_event_func(event_handle) == FALSE) { + infof(data,"WSACloseEvent failed (%d)",WSAGetLastError()); + } + + /* "Forget" pointers into the library we're about to free */ + create_event_func = NULL; + close_event_func = NULL; + event_select_func = NULL; + enum_netevents_func = NULL; + + /* We called LoadLibrary, so call FreeLibrary */ + if (!FreeLibrary(wsock2)) + infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError()); +#else + pfd[0].fd = sockfd; + pfd[0].events = POLLIN; + pfd[1].fd = 0; + pfd[1].events = POLLIN; + interval_ms = 1 * 1000; + + while (keepon) { + switch (Curl_poll(pfd, 2, interval_ms)) { + case -1: /* error, stop reading */ + keepon = FALSE; + continue; + case 0: /* timeout */ + break; + default: /* read! */ + if(pfd[1].revents & POLLIN) { /* read from stdin */ + unsigned char outbuf[2]; + int out_count = 0; + ssize_t bytes_written; + char *buffer = buf; + + nread = read(0, buf, 255); + + while(nread--) { + outbuf[0] = *buffer++; + out_count = 1; + if(outbuf[0] == CURL_IAC) + outbuf[out_count++] = CURL_IAC; + + Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, + out_count, &bytes_written); + } + } + + if(pfd[0].revents & POLLIN) { + /* This OUGHT to check the return code... */ + (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); + + /* if we receive 0 or less here, the server closed the connection and + we bail out from this! */ + if (nread <= 0) { + keepon = FALSE; + break; + } + + telrcv(conn, (unsigned char *)buf, nread); + + /* Negotiate if the peer has started negotiating, + 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(conn); + tn->already_negotiated = 1; + } + } + } + if(data->set.timeout) { + struct timeval now; /* current time */ + now = Curl_tvnow(); + if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) { + failf(data, "Time-out"); + code = CURLE_OPERATION_TIMEOUTED; + keepon = FALSE; + } + } + } +#endif + /* mark this as "no further transfer wanted" */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + + return code; +} +#endif diff --git a/Utilities/cmcurl/lib/telnet.h b/Utilities/cmcurl/lib/telnet.h new file mode 100644 index 0000000..693abf3 --- /dev/null +++ b/Utilities/cmcurl/lib/telnet.h @@ -0,0 +1,30 @@ +#ifndef __TELNET_H +#define __TELNET_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_TELNET +CURLcode Curl_telnet(struct connectdata *conn, bool *done); +CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode, bool premature); +#endif +#endif diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c new file mode 100644 index 0000000..0e2e7ab --- /dev/null +++ b/Utilities/cmcurl/lib/tftp.c @@ -0,0 +1,816 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_TFTP +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#if defined(WIN32) +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + + +#endif + +#include "urldata.h" +#include +#include "transfer.h" +#include "sendf.h" +#include "tftp.h" +#include "progress.h" +#include "connect.h" +#include "strerror.h" +#include "sockaddr.h" /* required for Curl_sockaddr_storage */ +#include "url.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "memory.h" +#include "select.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/* RFC2348 allows the block size to be negotiated, but we don't support that */ +#define TFTP_BLOCKSIZE 512 + +typedef enum { + TFTP_MODE_NETASCII=0, + TFTP_MODE_OCTET +} tftp_mode_t; + +typedef enum { + TFTP_STATE_START=0, + TFTP_STATE_RX, + TFTP_STATE_TX, + TFTP_STATE_FIN +} tftp_state_t; + +typedef enum { + TFTP_EVENT_INIT=0, + TFTP_EVENT_RRQ = 1, + TFTP_EVENT_WRQ = 2, + TFTP_EVENT_DATA = 3, + TFTP_EVENT_ACK = 4, + TFTP_EVENT_ERROR = 5, + TFTP_EVENT_TIMEOUT +} tftp_event_t; + +typedef enum { + TFTP_ERR_UNDEF=0, + TFTP_ERR_NOTFOUND, + TFTP_ERR_PERM, + TFTP_ERR_DISKFULL, + TFTP_ERR_ILLEGAL, + TFTP_ERR_UNKNOWNID, + TFTP_ERR_EXISTS, + TFTP_ERR_NOSUCHUSER, + TFTP_ERR_TIMEOUT, + TFTP_ERR_NORESPONSE +} tftp_error_t; + +typedef struct tftp_packet { + unsigned char data[2 + 2 + TFTP_BLOCKSIZE]; +} tftp_packet_t; + +typedef struct tftp_state_data { + tftp_state_t state; + tftp_mode_t mode; + tftp_error_t error; + struct connectdata *conn; + curl_socket_t sockfd; + int retries; + int retry_time; + int retry_max; + time_t start_time; + time_t max_time; + unsigned short block; + struct Curl_sockaddr_storage local_addr; + socklen_t local_addrlen; + struct Curl_sockaddr_storage remote_addr; + socklen_t remote_addrlen; + int rbytes; + int sbytes; + tftp_packet_t rpacket; + tftp_packet_t spacket; +} tftp_state_data_t; + + +/* Forward declarations */ +static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; +static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; +void tftp_set_timeouts(tftp_state_data_t *state) ; + +/********************************************************** + * + * tftp_set_timeouts - + * + * Set timeouts based on state machine state. + * Use user provided connect timeouts until DATA or ACK + * packet is received, then use user-provided transfer timeouts + * + * + **********************************************************/ +void tftp_set_timeouts(tftp_state_data_t *state) +{ + + struct SessionHandle *data = state->conn->data; + time_t maxtime, timeout; + + time(&state->start_time); + if(state->state == TFTP_STATE_START) { + /* Compute drop-dead time */ + maxtime = (time_t)(data->set.connecttimeout?data->set.connecttimeout:30); + state->max_time = state->start_time+maxtime; + + /* Set per-block timeout to total */ + timeout = maxtime ; + + /* Average restart after 5 seconds */ + state->retry_max = (int)(timeout/5); + + /* Compute the re-start interval to suit the timeout */ + state->retry_time = (int)(timeout/state->retry_max); + if(state->retry_time<1) + state->retry_time=1; + + } + else { + + /* Compute drop-dead time */ + maxtime = (time_t)(data->set.timeout?data->set.timeout:3600); + state->max_time = state->start_time+maxtime; + + /* Set per-block timeout to 10% of total */ + timeout = maxtime/10 ; + + /* Average reposting an ACK after 15 seconds */ + state->retry_max = (int)(timeout/15); + } + /* But bound the total number */ + if(state->retry_max<3) + state->retry_max=3; + + if(state->retry_max>50) + state->retry_max=50; + + /* Compute the re-ACK interval to suit the timeout */ + state->retry_time = (int)(timeout/state->retry_max); + if(state->retry_time<1) + state->retry_time=1; + + infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n", + state->state, (state->max_time-state->start_time), + state->retry_time, state->retry_max); +} + +/********************************************************** + * + * tftp_set_send_first + * + * Event handler for the START state + * + **********************************************************/ + +static void setpacketevent(tftp_packet_t *packet, unsigned short num) +{ + packet->data[0] = (unsigned char)(num >> 8); + packet->data[1] = (unsigned char)(num & 0xff); +} + + +static void setpacketblock(tftp_packet_t *packet, unsigned short num) +{ + packet->data[2] = (unsigned char)(num >> 8); + packet->data[3] = (unsigned char)(num & 0xff); +} + +static unsigned short getrpacketevent(tftp_packet_t *packet) +{ + return (unsigned short)((packet->data[0] << 8) | packet->data[1]); +} + +static unsigned short getrpacketblock(tftp_packet_t *packet) +{ + return (unsigned short)((packet->data[2] << 8) | packet->data[3]); +} + +static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) +{ + int sbytes; + const char *mode = "octet"; + char *filename; + struct SessionHandle *data = state->conn->data; + CURLcode res = CURLE_OK; + + /* Set ascii mode if -B flag was used */ + if(data->set.prefer_ascii) + mode = "netascii"; + + switch(event) { + + case TFTP_EVENT_INIT: /* Send the first packet out */ + case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */ + /* Increment the retry counter, quit if over the limit */ + state->retries++; + if(state->retries>state->retry_max) { + state->error = TFTP_ERR_NORESPONSE; + state->state = TFTP_STATE_FIN; + return res; + } + + if(data->set.upload) { + /* If we are uploading, send an WRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_WRQ); + state->conn->data->reqdata.upload_fromhere = (char *)&state->spacket.data[4]; + if(data->set.infilesize != -1) + Curl_pgrsSetUploadSize(data, data->set.infilesize); + } + else { + /* If we are downloading, send an RRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_RRQ); + } + /* As RFC3617 describes the separator slash is not actually part of the + file name so we skip the always-present first letter of the path string. */ + filename = curl_easy_unescape(data, &state->conn->data->reqdata.path[1], 0, + NULL); + snprintf((char *)&state->spacket.data[2], + TFTP_BLOCKSIZE, + "%s%c%s%c", filename, '\0', mode, '\0'); + sbytes = 4 + (int)strlen(filename) + (int)strlen(mode); + sbytes = sendto(state->sockfd, (void *)&state->spacket, + sbytes, 0, + state->conn->ip_addr->ai_addr, + state->conn->ip_addr->ai_addrlen); + if(sbytes < 0) { + failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + } + Curl_safefree(filename); + break; + + case TFTP_EVENT_ACK: /* Connected for transmit */ + infof(data, "%s\n", "Connected for transmit"); + state->state = TFTP_STATE_TX; + tftp_set_timeouts(state); + return tftp_tx(state, event); + + case TFTP_EVENT_DATA: /* connected for receive */ + infof(data, "%s\n", "Connected for receive"); + state->state = TFTP_STATE_RX; + tftp_set_timeouts(state); + return tftp_rx(state, event); + + case TFTP_EVENT_ERROR: + state->state = TFTP_STATE_FIN; + break; + + default: + failf(state->conn->data, "tftp_send_first: internal error\n"); + break; + } + return res; +} + +/********************************************************** + * + * tftp_rx + * + * Event handler for the RX state + * + **********************************************************/ +static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) +{ + int sbytes; + int rblock; + struct SessionHandle *data = state->conn->data; + + switch(event) { + + case TFTP_EVENT_DATA: + + /* Is this the block we expect? */ + rblock = getrpacketblock(&state->rpacket); + if ((state->block+1) != rblock) { + /* No, log it, up the retry count and fail if over the limit */ + infof(data, + "Received unexpected DATA packet block %d\n", rblock); + state->retries++; + if (state->retries>state->retry_max) { + failf(data, "tftp_rx: giving up waiting for block %d\n", + state->block+1); + return CURLE_TFTP_ILLEGAL; + } + } + /* This is the expected block. Reset counters and ACK it. */ + state->block = (unsigned short)rblock; + state->retries = 0; + setpacketevent(&state->spacket, TFTP_EVENT_ACK); + setpacketblock(&state->spacket, state->block); + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + if(sbytes < 0) { + failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + } + + /* Check if completed (That is, a less than full packet is received) */ + if (state->rbytes < (int)sizeof(state->spacket)){ + state->state = TFTP_STATE_FIN; + } + else { + state->state = TFTP_STATE_RX; + } + 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\n", state->retries); + if(state->retries > state->retry_max) { + state->error = TFTP_ERR_TIMEOUT; + state->state = TFTP_STATE_FIN; + } + else { + /* Resend the previous ACK */ + sbytes = sendto(state->sockfd, (void *)&state->spacket, + 4, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + } + } + break; + + case TFTP_EVENT_ERROR: + state->state = TFTP_STATE_FIN; + break; + + default: + failf(data, "%s\n", "tftp_rx: internal error"); + break; + } + Curl_pgrsSetDownloadCounter(data, + (curl_off_t) state->block*TFTP_BLOCKSIZE); + return CURLE_OK; +} + +/********************************************************** + * + * tftp_tx + * + * Event handler for the TX state + * + **********************************************************/ +static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) +{ + struct SessionHandle *data = state->conn->data; + int sbytes; + int rblock; + CURLcode res = CURLE_OK; + + switch(event) { + + case TFTP_EVENT_ACK: + /* Ack the packet */ + rblock = getrpacketblock(&state->rpacket); + + if(rblock != state->block) { + /* This isn't the expected block. Log it and up the retry counter */ + infof(data, "Received ACK for block %d, expecting %d\n", + rblock, state->block); + state->retries++; + /* Bail out if over the maximum */ + if(state->retries>state->retry_max) { + failf(data, "tftp_tx: giving up waiting for block %d ack", + state->block); + res = CURLE_SEND_ERROR; + } + else { + /* Re-send the data packet */ + sbytes = sendto(state->sockfd, (void *)&state->spacket, + 4+state->sbytes, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + res = CURLE_SEND_ERROR; + } + } + return res; + } + /* This is the expected packet. Reset the counters and send the next + block */ + state->block++; + state->retries = 0; + setpacketevent(&state->spacket, TFTP_EVENT_DATA); + setpacketblock(&state->spacket, state->block); + if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) { + state->state = TFTP_STATE_FIN; + return CURLE_OK; + } + res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes); + if(res) + return res; + sbytes = sendto(state->sockfd, (void *)state->spacket.data, + 4+state->sbytes, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + } + break; + + case TFTP_EVENT_TIMEOUT: + /* Increment the retry counter and log the timeout */ + state->retries++; + infof(data, "Timeout waiting for block %d ACK. " + " Retries = %d\n", state->retries); + /* Decide if we've had enough */ + if(state->retries > state->retry_max) { + state->error = TFTP_ERR_TIMEOUT; + state->state = TFTP_STATE_FIN; + } else { + /* Re-send the data packet */ + sbytes = sendto(state->sockfd, (void *)&state->spacket, + 4+state->sbytes, SEND_4TH_ARG, + (struct sockaddr *)&state->remote_addr, + state->remote_addrlen); + /* Check all sbytes were sent */ + if(sbytes<0) { + failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + } + } + break; + + case TFTP_EVENT_ERROR: + state->state = TFTP_STATE_FIN; + break; + + default: + failf(data, "%s\n", "tftp_tx: internal error"); + break; + } + + /* Update the progress meter */ + Curl_pgrsSetUploadCounter(data, (curl_off_t) state->block*TFTP_BLOCKSIZE); + + return res; +} + +/********************************************************** + * + * tftp_state_machine + * + * The tftp state machine event dispatcher + * + **********************************************************/ +static CURLcode tftp_state_machine(tftp_state_data_t *state, + tftp_event_t event) +{ + CURLcode res = CURLE_OK; + struct SessionHandle *data = state->conn->data; + switch(state->state) { + case TFTP_STATE_START: + DEBUGF(infof(data, "TFTP_STATE_START\n")); + res = tftp_send_first(state, event); + break; + case TFTP_STATE_RX: + DEBUGF(infof(data, "TFTP_STATE_RX\n")); + res = tftp_rx(state, event); + break; + case TFTP_STATE_TX: + DEBUGF(infof(data, "TFTP_STATE_TX\n")); + res = tftp_tx(state, event); + break; + case TFTP_STATE_FIN: + infof(data, "%s\n", "TFTP finished"); + break; + default: + DEBUGF(infof(data, "STATE: %d\n", state->state)); + failf(data, "%s\n", "Internal state machine error"); + res = CURLE_TFTP_ILLEGAL; + break; + } + return res; +} + + +/********************************************************** + * + * Curl_tftp_connect + * + * The connect callback + * + **********************************************************/ +CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) +{ + CURLcode code; + tftp_state_data_t *state; + int rc; + + state = conn->data->reqdata.proto.tftp = calloc(sizeof(tftp_state_data_t), + 1); + if(!state) + return CURLE_OUT_OF_MEMORY; + + conn->bits.close = FALSE; /* keep it open if possible */ + + state->conn = conn; + state->sockfd = state->conn->sock[FIRSTSOCKET]; + state->state = TFTP_STATE_START; + + ((struct sockaddr *)&state->local_addr)->sa_family = + conn->ip_addr->ai_family; + + tftp_set_timeouts(state); + + if(!conn->bits.reuse) { + /* If not reused, bind to any interface, random UDP port. If it is reused, + * this has already been done! + * + * We once used the size of the local_addr struct as the third argument for + * bind() to better work with IPv6 or whatever size the struct could have, + * but we learned that at least Tru64, AIX and IRIX *requires* the size of + * that argument to match the exact size of a 'sockaddr_in' struct when + * running IPv4-only. + * + * Therefore we use the size from the address we connected to, which we + * assume uses the same IP version and thus hopefully this works for both + * IPv4 and IPv6... + */ + rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, + conn->ip_addr->ai_addrlen); + if(rc) { + failf(conn->data, "bind() failed; %s\n", + Curl_strerror(conn, Curl_sockerrno())); + return CURLE_COULDNT_CONNECT; + } + } + + Curl_pgrsStartNow(conn->data); + + *done = TRUE; + code = CURLE_OK; + return(code); +} + +/********************************************************** + * + * Curl_tftp_done + * + * The done callback + * + **********************************************************/ +CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + (void)status; /* unused */ + (void)premature; /* not used */ + +#if 0 + free(conn->data->reqdata.proto.tftp); + conn->data->reqdata.proto.tftp = NULL; +#endif + Curl_pgrsDone(conn); + + return CURLE_OK; +} + + +/********************************************************** + * + * Curl_tftp + * + * The do callback + * + * This callback handles the entire TFTP transfer + * + **********************************************************/ + +CURLcode Curl_tftp(struct connectdata *conn, bool *done) +{ + struct SessionHandle *data = conn->data; + tftp_state_data_t *state = + (tftp_state_data_t *) conn->data->reqdata.proto.tftp; + tftp_event_t event; + CURLcode code; + int rc; + struct Curl_sockaddr_storage fromaddr; + socklen_t fromlen; + int check_time = 0; + + *done = TRUE; + + /* + Since connections can be re-used between SessionHandles, this might be a + connection already existing but on a fresh SessionHandle struct so we must + make sure we have a good 'struct TFTP' to play with. For new connections, + the struct TFTP is allocated and setup in the Curl_tftp_connect() function. + */ + if(!state) { + code = Curl_tftp_connect(conn, done); + if(code) + return code; + state = (tftp_state_data_t *)conn->data->reqdata.proto.tftp; + } + + /* Run the TFTP State Machine */ + for(tftp_state_machine(state, TFTP_EVENT_INIT); + state->state != TFTP_STATE_FIN; + tftp_state_machine(state, event) ) { + + /* Wait until ready to read or timeout occurs */ + rc=Curl_select(state->sockfd, CURL_SOCKET_BAD, state->retry_time * 1000); + + if(rc == -1) { + /* bail out */ + int error = Curl_sockerrno(); + failf(data, "%s\n", Curl_strerror(conn, error)); + event = TFTP_EVENT_ERROR; + } + else if (rc==0) { + /* A timeout occured */ + event = TFTP_EVENT_TIMEOUT; + + /* Force a look at transfer timeouts */ + check_time = 0; + + } + else { + + /* Receive the packet */ + fromlen=sizeof(fromaddr); + state->rbytes = recvfrom(state->sockfd, + (void *)&state->rpacket, sizeof(state->rpacket), + 0, (struct sockaddr *)&fromaddr, &fromlen); + if(state->remote_addrlen==0) { + memcpy(&state->remote_addr, &fromaddr, fromlen); + state->remote_addrlen = fromlen; + } + + /* Sanity check packet length */ + if (state->rbytes < 4) { + failf(conn->data, "Received too short packet\n"); + /* Not a timeout, but how best to handle it? */ + event = TFTP_EVENT_TIMEOUT; + } + else { + + /* The event is given by the TFTP packet time */ + event = (tftp_event_t)getrpacketevent(&state->rpacket); + + switch(event) { + case TFTP_EVENT_DATA: + /* Don't pass to the client empty or retransmitted packets */ + if (state->rbytes > 4 && + ((state->block+1) == getrpacketblock(&state->rpacket))) { + code = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)&state->rpacket.data[4], + state->rbytes-4); + if(code) + return code; + } + break; + case TFTP_EVENT_ERROR: + state->error = (tftp_error_t)getrpacketblock(&state->rpacket); + infof(conn->data, "%s\n", (char *)&state->rpacket.data[4]); + break; + case TFTP_EVENT_ACK: + break; + case TFTP_EVENT_RRQ: + case TFTP_EVENT_WRQ: + default: + failf(conn->data, "%s\n", "Internal error: Unexpected packet"); + break; + } + + /* Update the progress meter */ + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + } + } + + /* Check for transfer timeout every 10 blocks, or after timeout */ + if(check_time%10==0) { + time_t current; + time(¤t); + if(current>state->max_time) { + DEBUGF(infof(data, "timeout: %d > %d\n", + current, state->max_time)); + state->error = TFTP_ERR_TIMEOUT; + state->state = TFTP_STATE_FIN; + } + } + + } + + /* Tell curl we're done */ + code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + if(code) + return code; + + /* If we have encountered an error */ + if(state->error) { + + /* Translate internal error codes to curl error codes */ + switch(state->error) { + case TFTP_ERR_NOTFOUND: + code = CURLE_TFTP_NOTFOUND; + break; + case TFTP_ERR_PERM: + code = CURLE_TFTP_PERM; + break; + case TFTP_ERR_DISKFULL: + code = CURLE_TFTP_DISKFULL; + break; + case TFTP_ERR_ILLEGAL: + code = CURLE_TFTP_ILLEGAL; + break; + case TFTP_ERR_UNKNOWNID: + code = CURLE_TFTP_UNKNOWNID; + break; + case TFTP_ERR_EXISTS: + code = CURLE_TFTP_EXISTS; + break; + case TFTP_ERR_NOSUCHUSER: + code = CURLE_TFTP_NOSUCHUSER; + break; + case TFTP_ERR_TIMEOUT: + code = CURLE_OPERATION_TIMEOUTED; + break; + case TFTP_ERR_NORESPONSE: + code = CURLE_COULDNT_CONNECT; + break; + default: + code= CURLE_ABORTED_BY_CALLBACK; + break; + } + } + else + code = CURLE_OK; + return code; +} +#endif diff --git a/Utilities/cmcurl/lib/tftp.h b/Utilities/cmcurl/lib/tftp.h new file mode 100644 index 0000000..c712541 --- /dev/null +++ b/Utilities/cmcurl/lib/tftp.h @@ -0,0 +1,31 @@ +#ifndef __TFTP_H +#define __TFTP_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +#ifndef CURL_DISABLE_TFTP +CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done); +CURLcode Curl_tftp(struct connectdata *conn, bool *done); +CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode, bool premature); +#endif +#endif diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c new file mode 100644 index 0000000..bb9c0a1 --- /dev/null +++ b/Utilities/cmcurl/lib/timeval.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "timeval.h" + +#ifndef HAVE_GETTIMEOFDAY + +#ifdef WIN32 +#include + +static int gettimeofday(struct timeval *tp, void *nothing) +{ +#ifdef WITHOUT_MM_LIB + SYSTEMTIME st; + time_t tt; + struct tm tmtm; + /* mktime converts local to UTC */ + GetLocalTime (&st); + tmtm.tm_sec = st.wSecond; + tmtm.tm_min = st.wMinute; + tmtm.tm_hour = st.wHour; + tmtm.tm_mday = st.wDay; + tmtm.tm_mon = st.wMonth - 1; + tmtm.tm_year = st.wYear - 1900; + tmtm.tm_isdst = -1; + tt = mktime (&tmtm); + tp->tv_sec = tt; + tp->tv_usec = st.wMilliseconds * 1000; +#else + /** + ** The earlier time calculations using GetLocalTime + ** had a time resolution of 10ms.The timeGetTime, part + ** of multimedia apis offer a better time resolution + ** of 1ms.Need to link against winmm.lib for this + **/ + unsigned long Ticks = 0; + unsigned long Sec =0; + unsigned long Usec = 0; + Ticks = timeGetTime(); + + Sec = Ticks/1000; + Usec = (Ticks - (Sec*1000))*1000; + tp->tv_sec = Sec; + tp->tv_usec = Usec; +#endif /* WITHOUT_MM_LIB */ + (void)nothing; + return 0; +} +#else /* WIN32 */ +/* non-win32 version of Curl_gettimeofday() */ +static int gettimeofday(struct timeval *tp, void *nothing) +{ + (void)nothing; /* we don't support specific time-zones */ + tp->tv_sec = (long)time(NULL); + tp->tv_usec = 0; + return 0; +} +#endif /* WIN32 */ +#endif /* HAVE_GETTIMEOFDAY */ + +/* Return the current time in a timeval struct */ +struct timeval curlx_tvnow(void) +{ + struct timeval now; + (void)gettimeofday(&now, NULL); + return now; +} + +/* + * Make sure that the first argument is the more recent time, as otherwise + * we'll get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds. + */ +long curlx_tvdiff(struct timeval newer, struct timeval older) +{ + return (newer.tv_sec-older.tv_sec)*1000+ + (newer.tv_usec-older.tv_usec)/1000; +} + +/* + * Same as curlx_tvdiff but with full usec resolution. + * + * Returns: the time difference in seconds with subsecond resolution. + */ +double curlx_tvdiff_secs(struct timeval newer, struct timeval older) +{ + return (double)(newer.tv_sec-older.tv_sec)+ + (double)(newer.tv_usec-older.tv_usec)/1000000.0; +} + +/* return the number of seconds in the given input timeval struct */ +long Curl_tvlong(struct timeval t1) +{ + return t1.tv_sec; +} diff --git a/Utilities/cmcurl/lib/timeval.h b/Utilities/cmcurl/lib/timeval.h new file mode 100644 index 0000000..effd741 --- /dev/null +++ b/Utilities/cmcurl/lib/timeval.h @@ -0,0 +1,76 @@ +#ifndef __TIMEVAL_H +#define __TIMEVAL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* + * CAUTION: this header is designed to work when included by the app-side + * as well as the library. Do not mix with library internals! + */ + +#include "setup.h" + +#ifdef HAVE_SYS_TIME_H +#include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#else +#ifdef HAVE_TIME_H +#include +#endif +#endif + +#ifndef HAVE_STRUCT_TIMEVAL +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif + +struct timeval curlx_tvnow(void); + +/* + * Make sure that the first argument (t1) is the more recent time and t2 is + * the older time, as otherwise you get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds. + */ +long curlx_tvdiff(struct timeval t1, struct timeval t2); + +/* + * Same as curlx_tvdiff but with full usec resolution. + * + * Returns: the time difference in seconds with subsecond resolution. + */ +double curlx_tvdiff_secs(struct timeval t1, struct timeval t2); + +long Curl_tvlong(struct timeval t1); + +/* These two defines below exist to provide the older API for library + internals only. */ +#define Curl_tvnow() curlx_tvnow() +#define Curl_tvdiff(x,y) curlx_tvdiff(x,y) +#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y) + +#endif diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c new file mode 100644 index 0000000..5cb3361 --- /dev/null +++ b/Utilities/cmcurl/lib/transfer.c @@ -0,0 +1,2494 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +/* -- WIN32 approved -- */ +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#include + +#include "strtoofft.h" +#include "strequal.h" + +#ifdef WIN32 +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#ifndef HAVE_SOCKET +#error "We can't compile without socket() support!" +#endif + +#endif + +#include "urldata.h" +#include +#include "netrc.h" + +#include "content_encoding.h" +#include "hostip.h" +#include "transfer.h" +#include "sendf.h" +#include "speedcheck.h" +#include "progress.h" +#include "http.h" +#include "url.h" +#include "getinfo.h" +#include "sslgen.h" +#include "http_digest.h" +#include "http_ntlm.h" +#include "http_negotiate.h" +#include "share.h" +#include "memory.h" +#include "select.h" +#include "multiif.h" +#include "easyif.h" /* for Curl_convert_to_network prototype */ + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +/* The last #include file should be: */ +#include "memdebug.h" + +#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */ + +/* + * This function will call the read callback to fill our buffer with data + * to upload. + */ +CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) +{ + struct SessionHandle *data = conn->data; + size_t buffersize = (size_t)bytes; + int nread; + + if(conn->bits.upload_chunky) { + /* if chunked Transfer-Encoding */ + buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */ + data->reqdata.upload_fromhere += 10; /* 32bit hex + CRLF */ + } + + /* this function returns a size_t, so we typecast to int to prevent warnings + with picky compilers */ + nread = (int)conn->fread(data->reqdata.upload_fromhere, 1, + buffersize, conn->fread_in); + + if(nread == CURL_READFUNC_ABORT) { + failf(data, "operation aborted by callback\n"); + return CURLE_ABORTED_BY_CALLBACK; + } + + if(!conn->bits.forbidchunk && conn->bits.upload_chunky) { + /* if chunked Transfer-Encoding */ + char hexbuffer[11]; + int hexlen = snprintf(hexbuffer, sizeof(hexbuffer), + "%x\r\n", nread); + /* move buffer pointer */ + data->reqdata.upload_fromhere -= hexlen; + nread += hexlen; + + /* copy the prefix to the buffer */ + memcpy(data->reqdata.upload_fromhere, hexbuffer, hexlen); + + /* always append CRLF to the data */ + memcpy(data->reqdata.upload_fromhere + nread, "\r\n", 2); + + if((nread - hexlen) == 0) { + /* mark this as done once this chunk is transfered */ + data->reqdata.keep.upload_done = TRUE; + } + + nread+=2; /* for the added CRLF */ + } + + *nreadp = nread; + +#ifdef CURL_DOES_CONVERSIONS + if(data->set.prefer_ascii) { + CURLcode res; + res = Curl_convert_to_network(data, data->reqdata.upload_fromhere, nread); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(res != CURLE_OK) { + return(res); + } + } +#endif /* CURL_DOES_CONVERSIONS */ + + return CURLE_OK; +} + +/* + * checkhttpprefix() + * + * Returns TRUE if member of the list matches prefix of string + */ +static bool +checkhttpprefix(struct SessionHandle *data, + const char *s) +{ + struct curl_slist *head = data->set.http200aliases; + bool rc = FALSE; +#ifdef CURL_DOES_CONVERSIONS + /* convert from the network encoding using a scratch area */ + char *scratch = calloc(1, strlen(s)+1); + if (NULL == scratch) { + failf (data, "Failed to calloc memory for conversion!"); + return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ + } + strcpy(scratch, s); + if (CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { + /* Curl_convert_from_network calls failf if unsuccessful */ + free(scratch); + return FALSE; /* can't return CURLE_foobar so return FALSE */ + } + s = scratch; +#endif /* CURL_DOES_CONVERSIONS */ + + while (head) { + if (checkprefix(head->data, s)) { + rc = TRUE; + break; + } + head = head->next; + } + + if ((rc != TRUE) && (checkprefix("HTTP/", s))) { + rc = TRUE; + } + +#ifdef CURL_DOES_CONVERSIONS + free(scratch); +#endif /* CURL_DOES_CONVERSIONS */ + return rc; +} + +/* + * Curl_readrewind() rewinds the read stream. This typically (so far) only + * used for HTTP POST/PUT with multi-pass authentication when a sending was + * denied and a resend is necessary. + */ +CURLcode Curl_readrewind(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + + conn->bits.rewindaftersend = FALSE; /* we rewind now */ + + /* We have sent away data. If not using CURLOPT_POSTFIELDS or + CURLOPT_HTTPPOST, call app to rewind + */ + if(data->set.postfields || + (data->set.httpreq == HTTPREQ_POST_FORM)) + ; /* do nothing */ + else { + if(data->set.ioctl) { + curlioerr err; + + err = (data->set.ioctl) (data, CURLIOCMD_RESTARTREAD, + data->set.ioctl_client); + infof(data, "the ioctl callback returned %d\n", (int)err); + + if(err) { + /* FIXME: convert to a human readable error message */ + failf(data, "ioctl callback returned error %d\n", (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 + ourself with fseek() */ + if(data->set.fread == (curl_read_callback)fread) { + if(-1 != fseek(data->set.in, 0, SEEK_SET)) + /* successful rewind */ + return CURLE_OK; + } + + /* no callback set or failure aboe, makes us fail at once */ + failf(data, "necessary data rewind wasn't possible\n"); + return CURLE_SEND_FAIL_REWIND; + } + } + return CURLE_OK; +} + +static int data_pending(struct connectdata *conn) +{ + return Curl_ssl_data_pending(conn, FIRSTSOCKET); +} + +#ifndef MIN +#define MIN(a,b) (a < b ? a : b) +#endif + +static void read_rewind(struct connectdata *conn, + size_t thismuch) +{ + conn->read_pos -= thismuch; + conn->bits.stream_was_rewound = TRUE; + +#ifdef CURLDEBUG + { + char buf[512 + 1]; + size_t show; + + show = MIN(conn->buf_len - conn->read_pos, sizeof(buf)-1); + memcpy(buf, conn->master_buffer + conn->read_pos, show); + buf[show] = '\0'; + + DEBUGF(infof(conn->data, + "Buffer after stream rewind (read_pos = %d): [%s]", + conn->read_pos, buf)); + } +#endif +} + +/* + * Curl_readwrite() is the low-level function to be called when data is to + * be read and written to/from the connection. + */ +CURLcode Curl_readwrite(struct connectdata *conn, + bool *done) +{ + struct SessionHandle *data = conn->data; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + CURLcode result; + ssize_t nread; /* number of bytes read */ + int didwhat=0; + + curl_socket_t fd_read; + curl_socket_t fd_write; + int select_res; + + curl_off_t contentlength; + + /* 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_READ|KEEP_READ_HOLD)) == KEEP_READ) + fd_read = conn->sockfd; + else + fd_read = CURL_SOCKET_BAD; + + if((k->keepon & (KEEP_WRITE|KEEP_WRITE_HOLD)) == KEEP_WRITE) + fd_write = conn->writesockfd; + else + fd_write = CURL_SOCKET_BAD; + + select_res = Curl_select(fd_read, fd_write, 0); + if(select_res == CSELECT_ERR) { + failf(data, "select/poll returned error"); + return CURLE_SEND_ERROR; + } + + do { + /* 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_READ) && + ((select_res & CSELECT_IN) || conn->bits.stream_was_rewound)) { + /* read */ + bool is_empty_data = FALSE; + + /* This is where we loop until we have read everything there is to + read or we get a EWOULDBLOCK */ + do { + size_t buffersize = data->set.buffer_size? + data->set.buffer_size : BUFSIZE; + size_t bytestoread = buffersize; + int readrc; + + if (k->size != -1 && !k->header) { + /* make sure we don't read "too much" if we can help it since we + might be pipelining and then someone else might want to read what + follows! */ + curl_off_t totalleft = k->size - k->bytecount; + if(totalleft < (curl_off_t)bytestoread) + bytestoread = (size_t)totalleft; + } + + /* receive data from the network! */ + readrc = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread); + + /* subzero, this would've blocked */ + if(0 > readrc) + break; /* get out of loop */ + + /* get the CURLcode from the int */ + result = (CURLcode)readrc; + + if(result>0) + return result; + + if ((k->bytecount == 0) && (k->writebytecount == 0)) { + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + if(k->wait100_after_headers) + /* set time stamp to compare with when waiting for the 100 */ + k->start100 = Curl_tvnow(); + } + + didwhat |= KEEP_READ; + /* indicates data of zero size, i.e. empty file */ + is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0)); + + /* NULL terminate, allowing string ops to be used */ + if (0 < nread || is_empty_data) { + k->buf[nread] = 0; + } + else if (0 >= nread) { + /* if we receive 0 or less here, the server closed the connection + and we bail out from this! */ + + k->keepon &= ~KEEP_READ; + break; + } + + /* Default buffer to use when we write the buffer, it may be changed + in the flow below before the actual storing is done. */ + k->str = k->buf; + + /* Since this is a two-state thing, we check if we are parsing + headers at the moment or not. */ + if (k->header) { + /* we are in parse-the-header-mode */ + bool stop_reading = FALSE; + + /* header line within buffer loop */ + do { + size_t hbufp_index; + size_t rest_length; + size_t full_length; + int writetype; + + /* str_start is start of line within buf */ + k->str_start = k->str; + + /* data is in network encoding so use 0x0a instead of '\n' */ + k->end_ptr = memchr(k->str_start, 0x0a, nread); + + if (!k->end_ptr) { + /* Not a complete header line within buffer, append the data to + the end of the headerbuff. */ + + if (k->hbuflen + nread >= data->state.headersize) { + /* We enlarge the header buffer as it is too small */ + char *newbuff; + size_t newsize=CURLMAX((k->hbuflen+nread)*3/2, + data->state.headersize*2); + hbufp_index = k->hbufp - data->state.headerbuff; + newbuff = (char *)realloc(data->state.headerbuff, newsize); + if(!newbuff) { + failf (data, "Failed to alloc memory for big header!"); + return CURLE_OUT_OF_MEMORY; + } + data->state.headersize=newsize; + data->state.headerbuff = newbuff; + k->hbufp = data->state.headerbuff + hbufp_index; + } + memcpy(k->hbufp, k->str, nread); + k->hbufp += nread; + k->hbuflen += nread; + if (!k->headerline && (k->hbuflen>5)) { + /* make a first check that this looks like a HTTP header */ + if(!checkhttpprefix(data, data->state.headerbuff)) { + /* this is not the beginning of a HTTP first header line */ + k->header = FALSE; + k->badheader = HEADER_ALLBAD; + break; + } + } + + break; /* read more and try again */ + } + + /* decrease the size of the remaining (supposed) header line */ + rest_length = (k->end_ptr - k->str)+1; + nread -= (ssize_t)rest_length; + + k->str = k->end_ptr + 1; /* move past new line */ + + full_length = k->str - k->str_start; + + /* + * We're about to copy a chunk of data to the end of the + * already received header. We make sure that the full string + * fit in the allocated header buffer, or else we enlarge + * it. + */ + if (k->hbuflen + full_length >= + data->state.headersize) { + char *newbuff; + size_t newsize=CURLMAX((k->hbuflen+full_length)*3/2, + data->state.headersize*2); + hbufp_index = k->hbufp - data->state.headerbuff; + newbuff = (char *)realloc(data->state.headerbuff, newsize); + if(!newbuff) { + failf (data, "Failed to alloc memory for big header!"); + return CURLE_OUT_OF_MEMORY; + } + data->state.headersize= newsize; + data->state.headerbuff = newbuff; + k->hbufp = data->state.headerbuff + hbufp_index; + } + + /* copy to end of line */ + memcpy(k->hbufp, k->str_start, full_length); + k->hbufp += full_length; + k->hbuflen += full_length; + *k->hbufp = 0; + k->end_ptr = k->hbufp; + + k->p = data->state.headerbuff; + + /**** + * We now have a FULL header line that p points to + *****/ + + if(!k->headerline) { + /* the first read header */ + if((k->hbuflen>5) && + !checkhttpprefix(data, data->state.headerbuff)) { + /* this is not the beginning of a HTTP first header line */ + k->header = FALSE; + if(nread) + /* since there's more, this is a partial bad header */ + k->badheader = HEADER_PARTHEADER; + else { + /* this was all we read so its all a bad header */ + k->badheader = HEADER_ALLBAD; + nread = (ssize_t)rest_length; + } + break; + } + } + + /* headers are in network encoding so + use 0x0a and 0x0d instead of '\n' and '\r' */ + if ((0x0a == *k->p) || (0x0d == *k->p)) { + size_t headerlen; + /* Zero-length header line means end of headers! */ + +#ifdef CURL_DOES_CONVERSIONS + if (0x0d == *k->p) { + *k->p = '\r'; /* replace with CR in host encoding */ + k->p++; /* pass the CR byte */ + } + if (0x0a == *k->p) { + *k->p = '\n'; /* replace with LF in host encoding */ + k->p++; /* pass the LF byte */ + } +#else + if ('\r' == *k->p) + k->p++; /* pass the \r byte */ + if ('\n' == *k->p) + k->p++; /* pass the \n byte */ +#endif /* CURL_DOES_CONVERSIONS */ + + if(100 == k->httpcode) { + /* + * We have made a 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->write_after_100_header) { + + k->write_after_100_header = FALSE; + k->keepon |= KEEP_WRITE; + } + } + else { + k->header = FALSE; /* no more header to parse! */ + + if((k->size == -1) && !conn->bits.chunk && !conn->bits.close) + /* When connection is not to get closed, but no + Content-Length nor Content-Encoding chunked have been + received, there is no body in this response. We don't set + stop_reading TRUE since that would also prevent necessary + authentication actions to take place. */ + conn->bits.no_body = TRUE; + + } + + if (417 == k->httpcode) { + /* + * we got: "417 Expectation Failed" this means: + * we have made a HTTP call and our Expect Header + * seems to cause a problem => abort the write operations + * (or prevent them from starting). + */ + k->write_after_100_header = FALSE; + k->keepon &= ~KEEP_WRITE; + } + +#ifndef CURL_DISABLE_HTTP + /* + * When all the headers have been parsed, see if we should give + * up and return an error. + */ + if (Curl_http_should_fail(conn)) { + failf (data, "The requested URL returned error: %d", + k->httpcode); + return CURLE_HTTP_RETURNED_ERROR; + } +#endif /* CURL_DISABLE_HTTP */ + + /* now, only output this if the header AND body are requested: + */ + writetype = CLIENTWRITE_HEADER; + if (data->set.include_header) + writetype |= CLIENTWRITE_BODY; + + headerlen = k->p - data->state.headerbuff; + + result = Curl_client_write(conn, writetype, + data->state.headerbuff, + headerlen); + if(result) + return result; + + data->info.header_size += (long)headerlen; + conn->headerbytecount += (long)headerlen; + + conn->deductheadercount = + (100 == k->httpcode)?conn->headerbytecount:0; + + if (data->reqdata.resume_from && + (data->set.httpreq==HTTPREQ_GET) && + (k->httpcode == 416)) { + /* "Requested Range Not Satisfiable" */ + stop_reading = TRUE; + } + +#ifndef CURL_DISABLE_HTTP + if(!stop_reading) { + /* 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 metod was picked. */ + result = Curl_http_auth_act(conn); + + if(result) + return result; + + if(conn->bits.rewindaftersend) { + /* We rewind after a complete send, so thus we continue + sending now */ + infof(data, "Keep sending data to get tossed away!\n"); + k->keepon |= KEEP_WRITE; + } + } +#endif /* CURL_DISABLE_HTTP */ + + 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(conn->bits.no_body) + stop_reading = TRUE; + else { + /* If we know the expected size of this document, we set the + maximum download size to the size of the expected + document or else, we won't know when to stop reading! + + Note that we set the download maximum even if we read a + "Connection: close" header, to make sure that + "Content-Length: 0" still prevents us from attempting to + read the (missing) response-body. + */ + /* According to RFC2616 section 4.4, we MUST ignore + Content-Length: headers if we are now receiving data + using chunked Transfer-Encoding. + */ + if(conn->bits.chunk) + k->size=-1; + + } + if(-1 != k->size) { + /* We do this operation even if no_body is true, since this + data might be retrieved later with curl_easy_getinfo() + and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */ + + Curl_pgrsSetDownloadSize(data, k->size); + k->maxdownload = k->size; + } + /* If max download size is *zero* (nothing) we already + have nothing and can safely return ok now! */ + if(0 == k->maxdownload) + stop_reading = TRUE; + + if(stop_reading) { + /* we make sure that this socket isn't read more now */ + k->keepon &= ~KEEP_READ; + } + + break; /* exit header line loop */ + } + + /* We continue reading headers, so reset the line-based + header parsing variables hbufp && hbuflen */ + k->hbufp = data->state.headerbuff; + k->hbuflen = 0; + continue; + } + + /* + * Checks for special headers coming up. + */ + + 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! */ + int httpversion_major; + int nc; +#ifdef CURL_DOES_CONVERSIONS +#define HEADER1 scratch +#define SCRATCHSIZE 21 + CURLcode res; + char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */ + /* We can't really convert this yet because we + don't know if it's the 1st header line or the body. + So we do a partial conversion into a scratch area, + leaving the data at k->p as-is. + */ + strncpy(&scratch[0], k->p, SCRATCHSIZE); + scratch[SCRATCHSIZE] = 0; /* null terminate */ + res = Curl_convert_from_network(data, + &scratch[0], + SCRATCHSIZE); + if (CURLE_OK != res) { + /* Curl_convert_from_network calls failf if unsuccessful */ + return res; + } +#else +#define HEADER1 k->p /* no conversion needed, just use k->p */ +#endif /* CURL_DOES_CONVERSIONS */ + + nc = sscanf(HEADER1, + " HTTP/%d.%d %3d", + &httpversion_major, + &k->httpversion, + &k->httpcode); + if (nc==3) { + k->httpversion += 10 * httpversion_major; + } + else { + /* this is the real world, not a Nirvana + NCSA 1.5.x returns this crap when asked for HTTP/1.1 + */ + nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); + k->httpversion = 10; + + /* If user has set option HTTP200ALIASES, + compare header line against list of aliases + */ + if (!nc) { + if (checkhttpprefix(data, k->p)) { + nc = 1; + k->httpcode = 200; + k->httpversion = + (data->set.httpversion==CURL_HTTP_VERSION_1_0)? 10 : 11; + } + } + } + + if (nc) { + data->info.httpcode = k->httpcode; + data->info.httpversion = k->httpversion; + + /* + * 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 + * are definitely errors, so give up here. + */ + if (data->set.http_fail_on_error && (k->httpcode >= 400) && + ((k->httpcode != 401) || !data->set.userpwd) && + ((k->httpcode != 407) || !data->set.proxyuserpwd) ) { + + if (data->reqdata.resume_from && + (data->set.httpreq==HTTPREQ_GET) && + (k->httpcode == 416)) { + /* "Requested Range Not Satisfiable", just proceed and + pretend this is no error */ + } + else { + /* serious error, go home! */ + failf (data, "The requested URL returned error: %d", + k->httpcode); + return CURLE_HTTP_RETURNED_ERROR; + } + } + + if(k->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! */ + conn->bits.close = TRUE; + + switch(k->httpcode) { + case 204: + /* (quote from RFC2616, section 10.2.5): The server has + * fulfilled the request but does not need to return an + * entity-body ... The 204 response MUST NOT include a + * message-body, and thus is always terminated by the first + * empty line after the header fields. */ + /* FALLTHROUGH */ + case 416: /* Requested Range Not Satisfiable, it has the + Content-Length: set as the "real" document but no + actual response is sent. */ + case 304: + /* (quote from RFC2616, section 10.3.5): The 304 response + * MUST NOT contain a message-body, and thus is always + * terminated by the first empty line after the header + * fields. */ + k->size=0; + k->maxdownload=0; + k->ignorecl = TRUE; /* ignore Content-Length headers */ + break; + default: + /* nothing */ + break; + } + } + else { + k->header = FALSE; /* this is not a header line */ + break; + } + } + +#ifdef CURL_DOES_CONVERSIONS + /* convert from the network encoding */ + result = Curl_convert_from_network(data, k->p, strlen(k->p)); + if (CURLE_OK != result) { + return(result); + } + /* Curl_convert_from_network calls failf if unsuccessful */ +#endif /* CURL_DOES_CONVERSIONS */ + + /* Check for Content-Length: header lines to get size. Ignore + the header completely if we get a 416 response as then we're + resuming a document that we don't get, and this header contains + info about the true size of the document we didn't get now. */ + if (!k->ignorecl && !data->set.ignorecl && + checkprefix("Content-Length:", k->p)) { + contentlength = curlx_strtoofft(k->p+15, NULL, 10); + if (data->set.max_filesize && + contentlength > data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + if(contentlength >= 0) { + k->size = contentlength; + k->maxdownload = k->size; + } + else { + /* Negative Content-Length is really odd, and we know it + happens for example when older Apache servers send large + files */ + conn->bits.close = TRUE; + infof(data, "Negative content-length: %" FORMAT_OFF_T + ", closing after transfer\n", contentlength); + } + } + /* check for Content-Type: header lines to get the mime-type */ + else if (checkprefix("Content-Type:", k->p)) { + char *start; + char *end; + size_t len; + + /* Find the first non-space letter */ + for(start=k->p+13; + *start && ISSPACE(*start); + start++) + ; /* empty loop */ + + /* data is now in the host encoding so + use '\r' and '\n' instead of 0x0d and 0x0a */ + end = strchr(start, '\r'); + if(!end) + end = strchr(start, '\n'); + + if(end) { + /* skip all trailing space letters */ + for(; ISSPACE(*end) && (end > start); end--) + ; /* empty loop */ + + /* get length of the type */ + len = end-start+1; + + /* allocate memory of a cloned copy */ + Curl_safefree(data->info.contenttype); + + data->info.contenttype = malloc(len + 1); + if (NULL == data->info.contenttype) + return CURLE_OUT_OF_MEMORY; + + /* copy the content-type string */ + memcpy(data->info.contenttype, start, len); + data->info.contenttype[len] = 0; /* zero terminate */ + } + } +#ifndef CURL_DISABLE_HTTP + else if((k->httpversion == 10) && + conn->bits.httpproxy && + Curl_compareheader(k->p, + "Proxy-Connection:", "keep-alive")) { + /* + * When a 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. + */ + conn->bits.close = FALSE; /* don't close when done */ + infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); + } + else if((k->httpversion == 11) && + conn->bits.httpproxy && + Curl_compareheader(k->p, + "Proxy-Connection:", "close")) { + /* + * We get a HTTP/1.1 response from a proxy and it says it'll + * close down after this transfer. + */ + conn->bits.close = TRUE; /* close when done */ + infof(data, "HTTP/1.1 proxy connection set close!\n"); + } + else if((k->httpversion == 10) && + Curl_compareheader(k->p, "Connection:", "keep-alive")) { + /* + * A 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] */ + conn->bits.close = FALSE; /* don't close when done */ + infof(data, "HTTP/1.0 connection set to keep alive!\n"); + } + else if (Curl_compareheader(k->p, "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. + */ + conn->bits.close = TRUE; /* close when done */ + } + else if (Curl_compareheader(k->p, + "Transfer-Encoding:", "chunked")) { + /* + * [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. */ + conn->bits.chunk = TRUE; /* chunks coming our way */ + + /* init our chunky engine */ + Curl_httpchunk_init(conn); + } + + else if (checkprefix("Trailer:", k->p) || + checkprefix("Trailers:", k->p)) { + /* + * This test helps Curl_httpchunk_read() to determine to look + * for well formed trailers after the zero chunksize record. In + * this case a CRLF is required after the zero chunksize record + * when no trailers are sent, or after the last trailer record. + * + * It seems both Trailer: and Trailers: occur in the wild. + */ + conn->bits.trailerHdrPresent = TRUE; + } + + else if (checkprefix("Content-Encoding:", k->p) && + data->set.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 + */ + char *start; + + /* Find the first non-space letter */ + for(start=k->p+17; + *start && ISSPACE(*start); + start++) + ; /* empty loop */ + + /* Record the content-encoding for later use */ + if (checkprefix("identity", start)) + k->content_encoding = IDENTITY; + else if (checkprefix("deflate", start)) + k->content_encoding = DEFLATE; + else if (checkprefix("gzip", start) + || checkprefix("x-gzip", start)) + k->content_encoding = GZIP; + else if (checkprefix("compress", start) + || checkprefix("x-compress", start)) + k->content_encoding = COMPRESS; + } + else if (checkprefix("Content-Range:", k->p)) { + /* Content-Range: bytes [num]- + Content-Range: bytes: [num]- + Content-Range: [num]- + + 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! + */ + + char *ptr = k->p + 14; + + /* Move forward until first digit */ + while(*ptr && !ISDIGIT(*ptr)) + ptr++; + + k->offset = curlx_strtoofft(ptr, NULL, 10); + + if (data->reqdata.resume_from == k->offset) + /* we asked for a resume and we got it */ + k->content_range = TRUE; + } +#if !defined(CURL_DISABLE_COOKIES) + else if(data->cookies && + checkprefix("Set-Cookie:", k->p)) { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, + CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_add(data, + data->cookies, TRUE, k->p+11, + /* If there is a custom-set Host: name, use it + here, or else use real peer host name. */ + conn->allocptr.cookiehost? + conn->allocptr.cookiehost:conn->host.name, + data->reqdata.path); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } +#endif + else if(checkprefix("Last-Modified:", k->p) && + (data->set.timecondition || data->set.get_filetime) ) { + time_t secs=time(NULL); + k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"), + &secs); + if(data->set.get_filetime) + data->info.filetime = (long)k->timeofdoc; + } + else if((checkprefix("WWW-Authenticate:", k->p) && + (401 == k->httpcode)) || + (checkprefix("Proxy-authenticate:", k->p) && + (407 == k->httpcode))) { + result = Curl_http_input_auth(conn, k->httpcode, k->p); + if(result) + return result; + } + else if ((k->httpcode >= 300 && k->httpcode < 400) && + checkprefix("Location:", k->p)) { + if(data->set.http_follow_location) { + /* this is the URL that the server advices us to get instead */ + char *ptr; + char *start=k->p; + char backup; + + start += 9; /* pass "Location:" */ + + /* Skip spaces and tabs. We do this to support multiple + white spaces after the "Location:" keyword. */ + while(*start && ISSPACE(*start )) + start++; + + /* Scan through the string from the end to find the last + non-space. k->end_ptr points to the actual terminating zero + letter, move pointer one letter back and start from + there. This logic strips off trailing whitespace, but keeps + any embedded whitespace. */ + ptr = k->end_ptr-1; + while((ptr>=start) && ISSPACE(*ptr)) + ptr--; + ptr++; + + backup = *ptr; /* store the ending letter */ + if(ptr != start) { + *ptr = '\0'; /* zero terminate */ + data->reqdata.newurl = strdup(start); /* clone string */ + *ptr = backup; /* restore ending letter */ + if(!data->reqdata.newurl) + return CURLE_OUT_OF_MEMORY; + } + } + } +#endif /* CURL_DISABLE_HTTP */ + + /* + * End of header-checks. Write them to the client. + */ + + writetype = CLIENTWRITE_HEADER; + if (data->set.include_header) + writetype |= CLIENTWRITE_BODY; + + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, + k->p, (size_t)k->hbuflen, conn); + + result = Curl_client_write(conn, writetype, k->p, k->hbuflen); + if(result) + return result; + + data->info.header_size += (long)k->hbuflen; + conn->headerbytecount += (long)k->hbuflen; + + /* reset hbufp pointer && hbuflen */ + k->hbufp = data->state.headerbuff; + k->hbuflen = 0; + } + while (!stop_reading && *k->str); /* header line within buffer */ + + if(stop_reading) + /* We've stopped dealing with input, get out of the do-while loop */ + break; + + /* 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. */ + + } /* end if header mode */ + + /* 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->str && !k->header && (nread > 0 || is_empty_data)) { + + 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->protocol&PROT_HTTP) { + /* HTTP-only checks */ + + if (data->reqdata.newurl) { + if(conn->bits.close) { + /* Abort after the headers if "follow Location" is set + and we're set to close anyway. */ + k->keepon &= ~KEEP_READ; + *done = TRUE; + return CURLE_OK; + } + /* We have a new url to load, but since we want to be able + to re-use this connection properly, we read the full + response in "ignore more" */ + k->ignorebody = TRUE; + infof(data, "Ignoring the response-body\n"); + } + if (data->reqdata.resume_from && !k->content_range && + (data->set.httpreq==HTTPREQ_GET) && + !k->ignorebody) { + /* 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 doesn't seem to support " + "byte ranges. Cannot resume."); + return CURLE_HTTP_RANGE_ERROR; + } + + if(data->set.timecondition && !data->reqdata.range) { + /* A time condition has been set AND no ranges have been + requested. This seems to be what chapter 13.3.4 of + RFC 2616 defines to be the correct action for a + HTTP/1.1 client */ + if((k->timeofdoc > 0) && (data->set.timevalue > 0)) { + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + if(k->timeofdoc < data->set.timevalue) { + infof(data, + "The requested document is not new enough\n"); + *done = TRUE; + return CURLE_OK; + } + break; + case CURL_TIMECOND_IFUNMODSINCE: + if(k->timeofdoc > data->set.timevalue) { + infof(data, + "The requested document is not old enough\n"); + *done = TRUE; + return CURLE_OK; + } + break; + } /* switch */ + } /* two valid time strings */ + } /* we have a time condition */ + + } /* this is HTTP */ + } /* this is the first time we write a body part */ + k->bodywrites++; + + /* pass data to the debug function before it gets "dechunked" */ + if(data->set.verbose) { + if(k->badheader) { + Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff, + (size_t)k->hbuflen, conn); + if(k->badheader == HEADER_PARTHEADER) + Curl_debug(data, CURLINFO_DATA_IN, + k->str, (size_t)nread, conn); + } + else + Curl_debug(data, CURLINFO_DATA_IN, + k->str, (size_t)nread, conn); + } + +#ifndef CURL_DISABLE_HTTP + if(conn->bits.chunk) { + /* + * Bless me father for I have sinned. 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. The returned 'nread' holds the number of actual + * data it wrote to the client. */ + + CHUNKcode res = + Curl_httpchunk_read(conn, k->str, nread, &nread); + + if(CHUNKE_OK < res) { + if(CHUNKE_WRITE_ERROR == res) { + failf(data, "Failed writing data"); + return CURLE_WRITE_ERROR; + } + failf(data, "Received problem %d in the chunky parser", res); + return CURLE_RECV_ERROR; + } + else if(CHUNKE_STOP == res) { + /* we're done reading chunks! */ + k->keepon &= ~KEEP_READ; /* read no more */ + + /* There are now possibly N number of bytes at the end of the + str buffer that weren't written to the client, but we don't + care about them right now. */ + } + /* If it returned OK, we just keep going */ + } +#endif /* CURL_DISABLE_HTTP */ + + if((-1 != k->maxdownload) && + (k->bytecount + nread >= k->maxdownload)) { + /* The 'excess' amount below can't be more than BUFSIZE which + always will fit in a size_t */ + size_t excess = (size_t)(k->bytecount + nread - k->maxdownload); + if (excess > 0 && !k->ignorebody) { + infof(data, + "Rewinding stream by : %d" + " bytes on url %s (size = %" FORMAT_OFF_T + ", maxdownload = %" FORMAT_OFF_T + ", bytecount = %" FORMAT_OFF_T ", nread = %d)\n", + excess, conn->data->reqdata.path, + k->size, k->maxdownload, k->bytecount, nread); + read_rewind(conn, excess); + } + + nread = (ssize_t) (k->maxdownload - k->bytecount); + if(nread < 0 ) /* this should be unusual */ + nread = 0; + + k->keepon &= ~KEEP_READ; /* we're done reading */ + } + + k->bytecount += nread; + + Curl_pgrsSetDownloadCounter(data, k->bytecount); + + if(!conn->bits.chunk && (nread || k->badheader || is_empty_data)) { + /* If this is chunky transfer, it was already written */ + + if(k->badheader && !k->ignorebody) { + /* we parsed a piece of data wrongly assuming it was a header + and now we output it as body instead */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, + data->state.headerbuff, + k->hbuflen); + if(result) + return result; + } + if(k->badheader < HEADER_ALLBAD) { + /* This switch handles various content encodings. If there's an + error here, be sure to check over the almost identical code + in http_chunks.c. + Make sure that ALL_CONTENT_ENCODINGS contains all the + encodings handled here. */ +#ifdef HAVE_LIBZ + switch (k->content_encoding) { + case IDENTITY: +#endif + /* This is the default when the server sends no + Content-Encoding header. See Curl_readwrite_init; the + memset() call initializes k->content_encoding to zero. */ + if(!k->ignorebody) + result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str, + nread); +#ifdef HAVE_LIBZ + break; + + case DEFLATE: + /* Assume CLIENTWRITE_BODY; headers are not encoded. */ + if(!k->ignorebody) + result = Curl_unencode_deflate_write(conn, k, nread); + break; + + case GZIP: + /* Assume CLIENTWRITE_BODY; headers are not encoded. */ + if(!k->ignorebody) + result = Curl_unencode_gzip_write(conn, k, nread); + break; + + case COMPRESS: + default: + failf (data, "Unrecognized content encoding type. " + "libcurl understands `identity', `deflate' and `gzip' " + "content encodings."); + result = CURLE_BAD_CONTENT_ENCODING; + break; + } +#endif + } + k->badheader = HEADER_NORMAL; /* taken care of now */ + + if(result) + return result; + } + + } /* 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_READ; + } + + } while(data_pending(conn)); + + } /* if( read from socket ) */ + + /* If we still have writing to do, we check if we have a writable + socket. */ + if((k->keepon & KEEP_WRITE) && (select_res & CSELECT_OUT)) { + /* write */ + + int i, si; + ssize_t bytes_written; + bool writedone=TRUE; + + if ((k->bytecount == 0) && (k->writebytecount == 0)) + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + + didwhat |= KEEP_WRITE; + + /* + * We loop here to do the READ and SEND loop until we run out of + * data to send or until we get EWOULDBLOCK back + */ + do { + + /* only read more data if there's no upload data already + present in the upload buffer */ + if(0 == data->reqdata.upload_present) { + /* init the "upload from here" pointer */ + data->reqdata.upload_fromhere = k->uploadbuf; + + if(!k->upload_done) { + /* HTTP pollution, this should be written nicer to become more + protocol agnostic. */ + int fillcount; + + if(k->wait100_after_headers && + (data->reqdata.proto.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->wait100_after_headers = FALSE; /* headers sent */ + k->write_after_100_header = TRUE; /* wait for the header */ + k->keepon &= ~KEEP_WRITE; /* disable writing */ + k->start100 = Curl_tvnow(); /* timeout count starts now */ + didwhat &= ~KEEP_WRITE; /* we didn't write anything actually */ + break; + } + + result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount); + if(result) + return result; + + nread = (ssize_t)fillcount; + } + else + nread = 0; /* we're done uploading/reading */ + + /* the signed int typecase of nread of for systems that has + unsigned size_t */ + if (nread<=0) { + /* done */ + k->keepon &= ~KEEP_WRITE; /* we're done writing */ + writedone = TRUE; + + if(conn->bits.rewindaftersend) { + result = Curl_readrewind(conn); + if(result) + return result; + } + break; + } + + /* store number of bytes available for upload */ + data->reqdata.upload_present = nread; + + /* convert LF to CRLF if so asked */ +#ifdef CURL_DO_LINEEND_CONV + /* always convert if we're FTPing in ASCII mode */ + if ((data->set.crlf) || (data->set.prefer_ascii)) { +#else + if (data->set.crlf) { +#endif /* CURL_DO_LINEEND_CONV */ + if(data->state.scratch == NULL) + data->state.scratch = malloc(2*BUFSIZE); + if(data->state.scratch == NULL) { + 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. + */ + for(i = 0, si = 0; i < nread; i++, si++) { + if (data->reqdata.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 */ + data->set.infilesize++; + } + } + else + data->state.scratch[si] = data->reqdata.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 */ + data->reqdata.upload_fromhere = data->state.scratch; + + /* set the new amount too */ + data->reqdata.upload_present = nread; + } + } + } + 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(conn, + conn->writesockfd, /* socket to send to */ + data->reqdata.upload_fromhere, /* buffer pointer */ + data->reqdata.upload_present, /* buffer size */ + &bytes_written); /* actually send away */ + if(result) + return result; + + if(data->set.verbose) + /* show the data before we change the pointer upload_fromhere */ + Curl_debug(data, CURLINFO_DATA_OUT, data->reqdata.upload_fromhere, + (size_t)bytes_written, conn); + + if(data->reqdata.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 */ + data->reqdata.upload_present -= bytes_written; + + /* advance the pointer where to find the buffer when the next send + is to happen */ + data->reqdata.upload_fromhere += bytes_written; + + writedone = TRUE; /* we are done, stop the loop */ + } + else { + /* we've uploaded that buffer now */ + data->reqdata.upload_fromhere = k->uploadbuf; + data->reqdata.upload_present = 0; /* no more bytes left */ + + if(k->upload_done) { + /* switch off writing, we're done! */ + k->keepon &= ~KEEP_WRITE; /* we're done writing */ + writedone = TRUE; + } + } + + k->writebytecount += bytes_written; + Curl_pgrsSetUploadCounter(data, k->writebytecount); + + } while(!writedone); /* loop until we're done writing! */ + + } + + } while(0); /* just to break out from! */ + + k->now = Curl_tvnow(); + if(didwhat) { + /* Update read/write counters */ + if(k->bytecountp) + *k->bytecountp = k->bytecount; /* read count */ + if(k->writebytecountp) + *k->writebytecountp = k->writebytecount; /* write count */ + } + else { + /* no read no write, this is a timeout? */ + if (k->write_after_100_header) { + /* This should allow some time for the header to arrive, but only a + very short time as otherwise it'll be too much wasted times 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. + + */ + + long ms = Curl_tvdiff(k->now, k->start100); + if(ms > CURL_TIMEOUT_EXPECT_100) { + /* we've waited long enough, continue anyway */ + k->write_after_100_header = FALSE; + k->keepon |= KEEP_WRITE; + } + } + } + + if(Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, k->now); + if (result) + return result; + + if (data->set.timeout && + ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) { + if (k->size != -1) { + failf(data, "Operation timed out after %d seconds with %" + FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received", + data->set.timeout, k->bytecount, k->size); + } else { + failf(data, "Operation timed out after %d seconds with %" + FORMAT_OFF_T " bytes received", + data->set.timeout, k->bytecount); + } + return CURLE_OPERATION_TIMEOUTED; + } + + if(!k->keepon) { + /* + * The transfer has been performed. Just make some general checks before + * returning. + */ + + if(!(conn->bits.no_body) && (k->size != -1) && + (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 */ + !data->reqdata.newurl) { + failf(data, "transfer closed with %" FORMAT_OFF_T + " bytes remaining to read", + k->size - k->bytecount); + return CURLE_PARTIAL_FILE; + } + else if(!(conn->bits.no_body) && + conn->bits.chunk && + (data->reqdata.proto.http->chunk.state != CHUNK_STOP)) { + /* + * In chunked mode, return an error if the connection is closed prior to + * the empty (terminiating) 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"); + return CURLE_PARTIAL_FILE; + } + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + } + + /* Now update the "done" boolean we return */ + *done = (bool)(0 == (k->keepon&(KEEP_READ|KEEP_WRITE))); + + return CURLE_OK; +} + + +/* + * Curl_readwrite_init() inits the readwrite session. This is inited each time for a + * transfer, sometimes multiple times on the same SessionHandle + */ + +CURLcode Curl_readwrite_init(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + + /* NB: the content encoding software depends on this initialization of + Curl_transfer_keeper.*/ + memset(k, 0, sizeof(struct Curl_transfer_keeper)); + + k->start = Curl_tvnow(); /* start time */ + k->now = k->start; /* current time is now */ + k->header = TRUE; /* assume header */ + k->httpversion = -1; /* unknown at this point */ + + k->size = data->reqdata.size; + k->maxdownload = data->reqdata.maxdownload; + k->bytecountp = data->reqdata.bytecountp; + k->writebytecountp = data->reqdata.writebytecountp; + + k->bytecount = 0; + + k->buf = data->state.buffer; + k->uploadbuf = data->state.uploadbuffer; + k->maxfd = (conn->sockfd>conn->writesockfd? + conn->sockfd:conn->writesockfd)+1; + k->hbufp = data->state.headerbuff; + k->ignorebody=FALSE; + + Curl_pgrsTime(data, TIMER_PRETRANSFER); + Curl_speedinit(data); + + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + + if (!conn->bits.getheader) { + k->header = FALSE; + if(k->size > 0) + Curl_pgrsSetDownloadSize(data, k->size); + } + /* we want header and/or body, if neither then don't do this! */ + if(conn->bits.getheader || !conn->bits.no_body) { + + if(conn->sockfd != CURL_SOCKET_BAD) { + k->keepon |= KEEP_READ; + } + + if(conn->writesockfd != CURL_SOCKET_BAD) { + /* 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 && + (data->reqdata.proto.http->sending == HTTPSEND_BODY)) { + /* wait with write until we either got 100-continue or a timeout */ + k->write_after_100_header = TRUE; + k->start100 = k->start; + } + else { + if(data->state.expect100header) + /* when we've sent off the rest of the headers, we must await a + 100-continue */ + k->wait100_after_headers = TRUE; + k->keepon |= KEEP_WRITE; + } + } + } + + return CURLE_OK; +} + +/* + * 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 connectdata *conn, + curl_socket_t *sock, /* points to numsocks number + of sockets */ + int numsocks) +{ + struct SessionHandle *data = conn->data; + int bitmap = GETSOCK_BLANK; + int index = 0; + + if(numsocks < 2) + /* simple check but we might need two slots */ + return GETSOCK_BLANK; + + if(data->reqdata.keep.keepon & KEEP_READ) { + bitmap |= GETSOCK_READSOCK(index); + sock[index] = conn->sockfd; + } + + if(data->reqdata.keep.keepon & KEEP_WRITE) { + + if((conn->sockfd != conn->writesockfd) || + !(data->reqdata.keep.keepon & KEEP_READ)) { + /* only if they are not the same socket or we didn't have a readable + one, we increase index */ + if(data->reqdata.keep.keepon & KEEP_READ) + index++; /* increase index if we need two entries */ + sock[index] = conn->writesockfd; + } + + bitmap |= GETSOCK_WRITESOCK(index); + } + + return bitmap; +} + + +/* + * Transfer() + * + * This function is what performs the actual transfer. It is capable of + * doing both ways simultaneously. + * The transfer must already have been setup by a call to Curl_setup_transfer(). + * + * Note that headers are created in a preallocated buffer of a default size. + * That buffer can be enlarged on demand, but it is never shrunken again. + * + * Parts of this function was once written by the friendly Mark Butler + * . + */ + +static CURLcode +Transfer(struct connectdata *conn) +{ + CURLcode result; + struct SessionHandle *data = conn->data; + struct Curl_transfer_keeper *k = &data->reqdata.keep; + bool done=FALSE; + + if(!(conn->protocol & PROT_FILE)) + /* Only do this if we are not transferring FILE:, since the file: treatment + is different*/ + Curl_readwrite_init(conn); + + if((conn->sockfd == CURL_SOCKET_BAD) && + (conn->writesockfd == CURL_SOCKET_BAD)) + /* nothing to read, nothing to write, we're already OK! */ + return CURLE_OK; + + /* we want header and/or body, if neither then don't do this! */ + if(!conn->bits.getheader && conn->bits.no_body) + return CURLE_OK; + + while (!done) { + curl_socket_t fd_read; + curl_socket_t fd_write; + + /* limit-rate logic: if speed exceeds threshold, then do not include fd in + select set. The current speed is recalculated in each Curl_readwrite() + call */ + if ((k->keepon & KEEP_WRITE) && + (!data->set.max_send_speed || + (data->progress.ulspeed < data->set.max_send_speed) )) { + fd_write = conn->writesockfd; + k->keepon &= ~KEEP_WRITE_HOLD; + } + else { + fd_write = CURL_SOCKET_BAD; + if(k->keepon & KEEP_WRITE) + k->keepon |= KEEP_WRITE_HOLD; /* hold it */ + } + + if ((k->keepon & KEEP_READ) && + (!data->set.max_recv_speed || + (data->progress.dlspeed < data->set.max_recv_speed)) ) { + fd_read = conn->sockfd; + k->keepon &= ~KEEP_READ_HOLD; + } + else { + fd_read = CURL_SOCKET_BAD; + if(k->keepon & KEEP_READ) + k->keepon |= KEEP_READ_HOLD; /* hold it */ + } + + /* The *_HOLD logic is necessary since even though there might be no + traffic during the select interval, we still call Curl_readwrite() for + the timeout case and if we limit transfer speed we must make sure that + this function doesn't transfer anything while in HOLD status. */ + + switch (Curl_select(fd_read, fd_write, 1000)) { + case -1: /* select() error, stop reading */ +#ifdef EINTR + /* The EINTR is not serious, and it seems you might get this more + ofen when using the lib in a multi-threaded environment! */ + if(errno == EINTR) + ; + else +#endif + done = TRUE; /* no more read or write */ + continue; + case 0: /* timeout */ + default: /* readable descriptors */ + + result = Curl_readwrite(conn, &done); + break; + } + if(result) + return result; + + /* "done" signals to us if the transfer(s) are ready */ + } + + return CURLE_OK; +} + +/* + * Curl_pretransfer() is called immediately before a transfer starts. + */ +CURLcode Curl_pretransfer(struct SessionHandle *data) +{ + CURLcode res; + if(!data->change.url) { + /* we can't do anything wihout URL */ + failf(data, "No URL set!\n"); + return CURLE_URL_MALFORMAT; + } + + /* Init the SSL session ID cache here. We do it here since we want to do it + after the *_setopt() calls (that could change the size of the cache) but + before any transfer takes place. */ + res = Curl_ssl_initsessions(data, data->set.ssl.numsessions); + if(res) + return res; + + data->set.followlocation=0; /* reset the location-follow counter */ + data->state.this_is_a_follow = FALSE; /* reset this */ + data->state.errorbuf = FALSE; /* no error has occurred */ + + data->state.authproblem = FALSE; + data->state.authhost.want = data->set.httpauth; + data->state.authproxy.want = data->set.proxyauth; + + /* If there is a list of cookie files to read, do it now! */ + if(data->change.cookielist) { + Curl_cookie_loadfiles(data); + } + + /* Allow data->set.use_port to set which port to use. This needs to be + * disabled for example when we follow Location: headers to URLs using + * different ports! */ + data->state.allow_port = TRUE; + +#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) + /************************************************************* + * Tell signal handler to ignore SIGPIPE + *************************************************************/ + if(!data->set.no_signal) + data->state.prev_signal = signal(SIGPIPE, SIG_IGN); +#endif + + Curl_initinfo(data); /* reset session-specific information "variables" */ + Curl_pgrsStartNow(data); + + return CURLE_OK; +} + +/* + * Curl_posttransfer() is called immediately after a transfer ends + */ +CURLcode Curl_posttransfer(struct SessionHandle *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->progress.flags & PGRS_HIDE) && + !data->progress.callback) + /* only output if we don't use a progress callback and we're not hidden */ + fprintf(data->set.err, "\n"); + + return CURLE_OK; +} + +/* + * strlen_url() returns the length of the given URL if the spaces within the + * URL were properly URL encoded. + */ +static int strlen_url(char *url) +{ + char *ptr; + int newlen=0; + bool left=TRUE; /* left side of the ? */ + + for(ptr=url; *ptr; ptr++) { + switch(*ptr) { + case '?': + left=FALSE; + default: + newlen++; + break; + case ' ': + if(left) + newlen+=3; + else + newlen++; + break; + } + } + return newlen; +} + +/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in + * the source URL accordingly. + */ +static void strcpy_url(char *output, char *url) +{ + /* we must add this with whitespace-replacing */ + bool left=TRUE; + char *iptr; + char *optr = output; + for(iptr = url; /* read from here */ + *iptr; /* until zero byte */ + iptr++) { + switch(*iptr) { + case '?': + left=FALSE; + default: + *optr++=*iptr; + break; + case ' ': + if(left) { + *optr++='%'; /* add a '%' */ + *optr++='2'; /* add a '2' */ + *optr++='0'; /* add a '0' */ + } + else + *optr++='+'; /* add a '+' here */ + break; + } + } + *optr=0; /* zero terminate output buffer */ + +} + +/* + * 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. + */ +CURLcode Curl_follow(struct SessionHandle *data, + char *newurl, /* this 'newurl' is the Location: string, + and it must be malloc()ed before passed + here */ + bool retry) /* set TRUE if this is a request retry as + opposed to a real redirect following */ +{ + /* Location: redirect */ + char prot[16]; /* URL protocol string storage */ + char letter; /* used for a silly sscanf */ + size_t newlen; + char *newest; + + if(!retry) { + if ((data->set.maxredirs != -1) && + (data->set.followlocation >= data->set.maxredirs)) { + failf(data,"Maximum (%d) redirects followed", data->set.maxredirs); + return CURLE_TOO_MANY_REDIRECTS; + } + + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + + data->set.followlocation++; /* count location-followers */ + } + + if(data->set.http_auto_referer) { + /* We are asked to automatically set the previous URL as the + referer when we get the next URL. We pick the ->url field, + which may or may not be 100% correct */ + + if(data->change.referer_alloc) + /* If we already have an allocated referer, free this first */ + free(data->change.referer); + + data->change.referer = strdup(data->change.url); + data->change.referer_alloc = TRUE; /* yes, free this later */ + } + + if(2 != sscanf(newurl, "%15[^?&/:]://%c", prot, &letter)) { + /*** + *DANG* this is an RFC 2068 violation. The URL is supposed + to be absolute and this doesn't seem to be that! + *** + Instead, we have to TRY to append this new path to the old URL + to the right of the host part. Oh crap, this is doomed to cause + problems in the future... + */ + char *protsep; + char *pathsep; + + char *useurl = newurl; + size_t urllen; + + /* we must make our own copy of the URL to play with, as it may + point to read-only data */ + char *url_clone=strdup(data->change.url); + + if(!url_clone) + return CURLE_OUT_OF_MEMORY; /* skip out of this NOW */ + + /* protsep points to the start of the host name */ + protsep=strstr(url_clone, "//"); + if(!protsep) + protsep=url_clone; + else + protsep+=2; /* pass the slashes */ + + if('/' != newurl[0]) { + int level=0; + + /* 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's one available */ + pathsep = strrchr(protsep, '/'); + if(pathsep) + *pathsep=0; + + /* 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 */ + + if((useurl[0] == '.') && (useurl[1] == '/')) + useurl+=2; /* just skip 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; + } + } + } + } + else { + /* We got a new absolute path for this server, cut off from the + first slash */ + pathsep = strchr(protsep, '/'); + if(pathsep) { + /* When people use badly formatted URLs, such as + "http://www.url.com?dir=/home/daniel" we must not use the first + slash, if there's a ?-letter before it! */ + char *sep = strchr(protsep, '?'); + if(sep && (sep < pathsep)) + pathsep = sep; + *pathsep=0; + } + else { + /* There was no slash. Now, since we might be operating on a badly + formatted URL, such as "http://www.url.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) + *pathsep=0; + } + } + + /* If the new part contains a space, this is a mighty stupid redirect + but we still make an effort to do "right". To the left of a '?' + letter we replace each space with %20 while it is replaced with '+' + on the right side of the '?' letter. + */ + newlen = strlen_url(useurl); + + urllen = strlen(url_clone); + + newest=(char *)malloc( urllen + 1 + /* possible slash */ + newlen + 1 /* zero byte */); + + if(!newest) { + free(url_clone); /* don't leak this */ + return CURLE_OUT_OF_MEMORY; /* go out from this */ + } + + /* copy over the root url part */ + memcpy(newest, url_clone, urllen); + + /* check if we need to append a slash */ + if(('/' == useurl[0]) || (protsep && !*protsep)) + ; + else + newest[urllen++]='/'; + + /* then append the new piece on the right side */ + strcpy_url(&newest[urllen], useurl); + + free(newurl); /* newurl is the allocated pointer */ + free(url_clone); + newurl = newest; + } + else { + /* This is an absolute URL, don't allow the custom port number */ + data->state.allow_port = FALSE; + + if(strchr(newurl, ' ')) { + /* This new URL contains at least one space, this is a mighty stupid + redirect but we still make an effort to do "right". */ + newlen = strlen_url(newurl); + + newest = malloc(newlen+1); /* get memory for this */ + if(newest) { + strcpy_url(newest, newurl); /* create a space-free URL */ + + free(newurl); /* that was no good */ + newurl = newest; /* use this instead now */ + } + } + + } + + if(data->change.url_alloc) + free(data->change.url); + else + data->change.url_alloc = TRUE; /* the URL is allocated */ + + data->change.url = newurl; + newurl = NULL; /* don't free! */ + + infof(data, "Issue another request to this URL: '%s'\n", data->change.url); + + /* + * We get here when the HTTP code is 300-399 (and 401). We need to perform + * differently based on exactly what return code there was. + * + * News from 7.10.6: we can also get here on a 401 or 407, in case we act on + * a HTTP (proxy-) authentication scheme other than Basic. + */ + switch(data->info.httpcode) { + /* 401 - Act on a www-authentication, we keep on moving and do the + Authorization: XXXX header in the HTTP request code snippet */ + /* 407 - Act on a proxy-authentication, we keep on moving and do the + Proxy-Authorization: XXXX header in the HTTP request code snippet */ + /* 300 - Multiple Choices */ + /* 306 - Not used */ + /* 307 - Temporary Redirect */ + default: /* for all above (and the unknown ones) */ + /* 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 RFC2616, section 10.3.2): + * + * Note: When automatically redirecting a POST request after receiving a + * 301 status code, some existing HTTP/1.0 user agents will erroneously + * change it into a GET request. + * + * ---- + * + * Warning: Because most of importants user agents do this obvious RFC2616 + * violation, many webservers expect this misbehavior. So these servers + * often answers to a POST request with an error page. To be sure that + * libcurl gets the page that most user agents would get, libcurl has to + * force GET: + */ + if( data->set.httpreq == HTTPREQ_POST + || data->set.httpreq == HTTPREQ_POST_FORM) { + infof(data, + "Violate RFC 2616/10.3.2 and switch from POST to GET\n"); + data->set.httpreq = HTTPREQ_GET; + } + break; + case 302: /* Found */ + /* (From 10.3.3) + + Note: RFC 1945 and RFC 2068 specify that the client is not allowed + to change the method on the redirected request. However, most + existing user agent implementations treat 302 as if it were a 303 + response, performing a GET on the Location field-value regardless + of the original request method. The status codes 303 and 307 have + been added for servers that wish to make unambiguously clear which + kind of reaction is expected of the client. + + (From 10.3.4) + + Note: Many pre-HTTP/1.1 user agents do not understand the 303 + status. When interoperability with such clients is a concern, the + 302 status code may be used instead, since most user agents react + to a 302 response as described here for 303. + */ + case 303: /* See Other */ + /* Disable both types of POSTs, since doing a second POST when + * following isn't what anyone would want! */ + if(data->set.httpreq != HTTPREQ_GET) { + data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ + infof(data, "Disables POST, goes with %s\n", + data->set.opt_no_body?"HEAD":"GET"); + } + break; + case 304: /* Not Modified */ + /* 304 means we did a conditional request and it was "Not modified". + * 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 + * via the proxy. 305 responses MUST only be generated by origin + * servers." + */ + break; + } + Curl_pgrsTime(data, TIMER_REDIRECT); + Curl_pgrsResetTimes(data); + + return CURLE_OK; +} + +static CURLcode +Curl_connect_host(struct SessionHandle *data, + struct connectdata **conn) +{ + CURLcode res = CURLE_OK; + int urlchanged = FALSE; + + do { + bool async; + bool protocol_done=TRUE; /* will be TRUE always since this is only used + within the easy interface */ + Curl_pgrsTime(data, TIMER_STARTSINGLE); + data->change.url_changed = FALSE; + res = Curl_connect(data, conn, &async, &protocol_done); + + if((CURLE_OK == res) && async) { + /* Now, if async is TRUE here, we need to wait for the name + to resolve */ + res = Curl_wait_for_resolv(*conn, NULL); + if(CURLE_OK == res) + /* Resolved, continue with the connection */ + res = Curl_async_resolved(*conn, &protocol_done); + else + /* if we can't resolve, we kill this "connection" now */ + (void)Curl_disconnect(*conn); + } + if(res) + break; + + /* If a callback (or something) has altered the URL we should use within + the Curl_connect(), we detect it here and act as if we are redirected + to the new URL */ + urlchanged = data->change.url_changed; + if ((CURLE_OK == res) && urlchanged) { + res = Curl_done(conn, res, FALSE); + if(CURLE_OK == res) { + char *gotourl = strdup(data->change.url); + res = Curl_follow(data, gotourl, FALSE); + if(res) + free(gotourl); + } + } + } while (urlchanged && res == CURLE_OK); + + return res; +} + +/* Returns TRUE and sets '*url' if a request retry is wanted */ +bool Curl_retry_request(struct connectdata *conn, + char **url) +{ + bool retry = FALSE; + struct SessionHandle *data = conn->data; + + if((data->reqdata.keep.bytecount+conn->headerbytecount == 0) && + conn->bits.reuse && + !conn->bits.no_body) { + /* We got no data, we attempted to re-use a connection and yet we want a + "body". This might happen if the connection was left alive when we were + done using it before, but that was closed when we wanted to read from + it again. Bad luck. Retry the same request on a fresh connect! */ + infof(conn->data, "Connection died, retrying a fresh connect\n"); + *url = strdup(conn->data->change.url); + + conn->bits.close = TRUE; /* close this connection */ + 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 + transfered! */ + retry = TRUE; + } + + return retry; +} + +/* + * Curl_perform() is the internal high-level function that gets called by the + * external curl_easy_perform() function. It inits, performs and cleans up a + * single file transfer. + */ +CURLcode Curl_perform(struct SessionHandle *data) +{ + CURLcode res; + CURLcode res2; + struct connectdata *conn=NULL; + char *newurl = NULL; /* possibly a new URL to follow to! */ + bool retry = FALSE; + + data->state.used_interface = Curl_if_easy; + + res = Curl_pretransfer(data); + if(res) + return res; + + /* + * It is important that there is NO 'return' from this function at any other + * place than falling down to the end of the function! This is because we + * have cleanup stuff that must be done before we get back, and that is only + * performed after this do-while loop. + */ + + do { + res = Curl_connect_host(data, &conn); /* primary connection */ + + if(res == CURLE_OK) { + bool do_done; + if(data->set.connect_only) { + /* keep connection open for application to use the socket */ + conn->bits.close = FALSE; + res = Curl_done(&conn, CURLE_OK, FALSE); + break; + } + res = Curl_do(&conn, &do_done); + + if(res == CURLE_OK) { + res = Transfer(conn); /* now fetch that URL please */ + if(res == CURLE_OK) { + retry = Curl_retry_request(conn, &newurl); + + if(!retry) + /* + * We must duplicate the new URL here as the connection data may + * be free()ed in the Curl_done() function. + */ + newurl = data->reqdata.newurl?strdup(data->reqdata.newurl):NULL; + } + else { + /* The transfer phase returned error, we mark the connection to get + * closed to prevent being re-used. This is becasue we can't + * possibly know if the connection is in a good shape or not now. */ + conn->bits.close = TRUE; + + if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { + /* if we failed anywhere, we must clean up the secondary socket if + it was used */ + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + } + } + + /* Always run Curl_done(), even if some of the previous calls + failed, but return the previous (original) error code */ + res2 = Curl_done(&conn, res, FALSE); + + if(CURLE_OK == res) + res = res2; + } + else + /* Curl_do() failed, clean up left-overs in the done-call */ + res2 = Curl_done(&conn, res, FALSE); + + /* + * Important: 'conn' cannot be used here, since it may have been closed + * in 'Curl_done' or other functions. + */ + + if((res == CURLE_OK) && newurl) { + res = Curl_follow(data, newurl, retry); + if(CURLE_OK == res) { + newurl = NULL; + continue; + } + } + } + break; /* it only reaches here when this shouldn't loop */ + + } while(1); /* loop if Location: */ + + if(newurl) + free(newurl); + + if(res && !data->state.errorbuf) { + /* + * As an extra precaution: if no error string has been set and there was + * an error, use the strerror() string or if things are so bad that not + * even that is good, set a bad string that mentions the error code. + */ + const char *str = curl_easy_strerror(res); + if(!str) + failf(data, "unspecified error %d", (int)res); + else + failf(data, "%s", str); + } + + /* run post-transfer uncondionally, but don't clobber the return code if + we already have an error code recorder */ + res2 = Curl_posttransfer(data); + if(!res && res2) + res = res2; + + return res; +} + +/* + * Curl_setup_transfer() is called to setup some basic properties for the + * upcoming transfer. + */ +CURLcode +Curl_setup_transfer( + struct connectdata *c_conn, /* connection 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 */ + curl_off_t *bytecountp, /* return number of bytes read or NULL */ + int writesockindex, /* socket index to write to, it may very + well be the same we read from. -1 + disables */ + curl_off_t *writecountp /* return number of bytes written or + NULL */ + ) +{ + struct connectdata *conn = (struct connectdata *)c_conn; + struct SessionHandle *data = conn->data; + + if(!conn) + return CURLE_BAD_FUNCTION_ARGUMENT; + + curlassert((sockindex <= 1) && (sockindex >= -1)); + + /* now copy all input parameters */ + conn->sockfd = sockindex == -1 ? + CURL_SOCKET_BAD : conn->sock[sockindex]; + conn->writesockfd = writesockindex == -1 ? + CURL_SOCKET_BAD:conn->sock[writesockindex]; + conn->bits.getheader = getheader; + + data->reqdata.size = size; + data->reqdata.bytecountp = bytecountp; + data->reqdata.writebytecountp = writecountp; + + return CURLE_OK; +} diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h new file mode 100644 index 0000000..3c415cc --- /dev/null +++ b/Utilities/cmcurl/lib/transfer.h @@ -0,0 +1,51 @@ +#ifndef __TRANSFER_H +#define __TRANSFER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ +CURLcode Curl_perform(struct SessionHandle *data); +CURLcode Curl_pretransfer(struct SessionHandle *data); +CURLcode Curl_second_connect(struct connectdata *conn); +CURLcode Curl_posttransfer(struct SessionHandle *data); +CURLcode Curl_follow(struct SessionHandle *data, char *newurl, bool retry); +CURLcode Curl_readwrite(struct connectdata *conn, bool *done); +int Curl_single_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); +CURLcode Curl_readwrite_init(struct connectdata *conn); +CURLcode Curl_readrewind(struct connectdata *conn); +CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); +bool Curl_retry_request(struct connectdata *conn, char **url); + +/* This sets up a forthcoming transfer */ +CURLcode +Curl_setup_transfer (struct connectdata *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 */ + curl_off_t *bytecountp, /* return number of bytes read */ + int writesockindex, /* socket index to write to, it may + very well be the same we read from. + -1 disables */ + curl_off_t *writecountp /* return number of bytes written */ +); +#endif diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c new file mode 100644 index 0000000..da12231 --- /dev/null +++ b/Utilities/cmcurl/lib/url.c @@ -0,0 +1,4252 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* -- WIN32 approved -- */ + +#include "setup.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include + +#ifdef WIN32 +#include +#include +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef VMS +#include +#include +#endif + +#ifdef HAVE_SETJMP_H +#include +#endif + +#ifndef HAVE_SOCKET +#error "We can't compile without socket() support!" +#endif +#endif + +#ifdef USE_LIBIDN +#include +#include +#include +#ifdef HAVE_IDN_FREE_H +#include +#else +void idn_free (void *ptr); /* prototype from idn-free.h, not provided by + libidn 0.4.5's make install! */ +#endif +#ifndef HAVE_IDN_FREE +/* if idn_free() was not found in this version of libidn, use plain free() + instead */ +#define idn_free(x) (free)(x) +#endif +#endif /* USE_LIBIDN */ + +#include "urldata.h" +#include "netrc.h" + +#include "formdata.h" +#include "base64.h" +#include "sslgen.h" +#include "hostip.h" +#include "transfer.h" +#include "sendf.h" +#include "progress.h" +#include "cookie.h" +#include "strequal.h" +#include "strerror.h" +#include "escape.h" +#include "strtok.h" +#include "share.h" +#include "content_encoding.h" +#include "http_digest.h" +#include "http_negotiate.h" +#include "select.h" +#include "multiif.h" +#include "easyif.h" + +/* And now for the protocols */ +#include "ftp.h" +#include "dict.h" +#include "telnet.h" +#include "tftp.h" +#include "http.h" +#include "file.h" +#include "ldap.h" +#include "ssh.h" +#include "url.h" +#include "connect.h" +#include "inet_ntop.h" +#include "http_ntlm.h" +#include "socks.h" +#include + +#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) +#include "inet_ntoa_r.h" +#endif + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#ifdef HAVE_KRB4 +#include "krb4.h" +#endif +#include "memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/* Local static prototypes */ +static long ConnectionKillOne(struct SessionHandle *data); +static bool ConnectionExists(struct SessionHandle *data, + struct connectdata *needle, + struct connectdata **usethis); +static long ConnectionStore(struct SessionHandle *data, + struct connectdata *conn); +static bool IsPipeliningPossible(struct SessionHandle *handle); +static bool IsPipeliningEnabled(struct SessionHandle *handle); +static void conn_free(struct connectdata *conn); + +static void signalPipeClose(struct curl_llist *pipe); + +#define MAX_PIPELINE_LENGTH 5 + +/* + * We use this ZERO_NULL to avoid picky compiler warnings, + * when assigning a NULL pointer to a function pointer var. + */ + +#define ZERO_NULL 0 + +#ifndef USE_ARES +/* not for ares builds */ + +#ifndef WIN32 +/* not for WIN32 builds */ + +#ifdef HAVE_SIGSETJMP +extern sigjmp_buf curl_jmpenv; +#endif + +#ifdef SIGALRM +static +RETSIGTYPE alarmfunc(int sig) +{ + /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ + (void)sig; +#ifdef HAVE_SIGSETJMP + siglongjmp(curl_jmpenv, 1); +#endif + /*return;*/ /* not reahed, and has no effect anyway */ +} +#endif /* SIGALRM */ +#endif /* WIN32 */ +#endif /* USE_ARES */ + +void Curl_safefree(void *ptr) +{ + if(ptr) + free(ptr); +} + +static void close_connections(struct SessionHandle *data) +{ + /* Loop through all open connections and kill them one by one */ + while(-1 != ConnectionKillOne(data)) + ; /* empty loop */ +} + +/* + * This is the internal function curl_easy_cleanup() calls. This should + * cleanup and free all resources associated with this sessionhandle. + * + * NOTE: if we ever add something that attempts to write to a socket or + * similar here, we must ignore SIGPIPE first. It is currently only done + * when curl_easy_perform() is invoked. + */ + +CURLcode Curl_close(struct SessionHandle *data) +{ + struct Curl_multi *m = data->multi; + +#ifdef CURLDEBUG + /* only for debugging, scan through all connections and see if there's a + pipe reference still identifying this handle */ + + if(data->state.is_in_pipeline) + fprintf(stderr, "CLOSED when in pipeline!\n"); + + if(data->state.connc && data->state.connc->type == CONNCACHE_MULTI) { + struct conncache *c = data->state.connc; + int i; + struct curl_llist *pipe; + struct curl_llist_element *curr; + struct connectdata *connptr; + + for(i=0; i< c->num; i++) { + connptr = c->connects[i]; + if(!connptr) + continue; + + pipe = connptr->send_pipe; + if(pipe) { + for (curr = pipe->head; curr; curr=curr->next) { + if(data == (struct SessionHandle *) curr->ptr) { + fprintf(stderr, + "MAJOR problem we %p are still in send pipe for %p done %d\n", + data, connptr, connptr->bits.done); + } + } + } + pipe = connptr->recv_pipe; + if(pipe) { + for (curr = pipe->head; curr; curr=curr->next) { + if(data == (struct SessionHandle *) curr->ptr) { + fprintf(stderr, + "MAJOR problem we %p are still in recv pipe for %p done %d\n", + data, connptr, connptr->bits.done); + } + } + } + } + } +#endif + + if(m) + /* This handle is still part of a multi handle, take care of this first + and detach this handle from there. */ + Curl_multi_rmeasy(data->multi, data); + + data->magic = 0; /* force a clear AFTER the possibly enforced removal from + the multi handle, since that function uses the magic + field! */ + + if(data->state.connc) { + + if(data->state.connc->type == CONNCACHE_PRIVATE) { + /* close all connections still alive that are in the private connection + cache, as we no longer have the pointer left to the shared one. */ + close_connections(data); + + /* free the connection cache if allocated privately */ + Curl_rm_connc(data->state.connc); + } + } + + if(data->state.shared_conn) { + /* marked to be used by a pending connection so we can't kill this handle + just yet */ + data->state.closed = TRUE; + return CURLE_OK; + } + + if ( ! (data->share && data->share->hostcache) ) { + if ( !Curl_global_host_cache_use(data)) { + Curl_hash_destroy(data->dns.hostcache); + } + } + + /* Free the pathbuffer */ + Curl_safefree(data->reqdata.pathbuffer); + Curl_safefree(data->reqdata.proto.generic); + + /* Close down all open SSL info and sessions */ + Curl_ssl_close_all(data); + Curl_safefree(data->state.first_host); + Curl_safefree(data->state.scratch); + + if(data->change.referer_alloc) + free(data->change.referer); + + if(data->change.url_alloc) + free(data->change.url); + + Curl_safefree(data->state.headerbuff); + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + if(data->set.cookiejar) { + if(data->change.cookielist) { + /* If there is a list of cookie files to read, do it first so that + we have all the told files read before we write the new jar */ + Curl_cookie_loadfiles(data); + } + + /* we have a "destination" for all the cookies to get dumped to */ + if(Curl_cookie_output(data->cookies, data->set.cookiejar)) + infof(data, "WARNING: failed to save cookies in %s\n", + data->set.cookiejar); + } + else { + if(data->change.cookielist) + /* since nothing is written, we can just free the list of cookie file + names */ + curl_slist_free_all(data->change.cookielist); /* clean up list */ + } + + if( !data->share || (data->cookies != data->share->cookies) ) { + Curl_cookie_cleanup(data->cookies); + } + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); +#endif + + Curl_digest_cleanup(data); + + Curl_safefree(data->info.contenttype); + + /* this destroys the channel and we cannot use it anymore after this */ + ares_destroy(data->state.areschannel); + +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) + /* close iconv conversion descriptors */ + if (data->inbound_cd != (iconv_t)-1) { + iconv_close(data->inbound_cd); + } + if (data->outbound_cd != (iconv_t)-1) { + iconv_close(data->outbound_cd); + } + if (data->utf8_cd != (iconv_t)-1) { + iconv_close(data->utf8_cd); + } +#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ + + /* No longer a dirty share, if it exists */ + if (data->share) + data->share->dirty--; + + free(data); + return CURLE_OK; +} + +/* create a connection cache of a private or multi type */ +struct conncache *Curl_mk_connc(int type, + int amount) /* set -1 to use default */ +{ + /* It is subject for debate how many default connections to have for a multi + connection cache... */ + int default_amount = amount == -1? + ((type == CONNCACHE_PRIVATE)?5:10):amount; + struct conncache *c; + + c= calloc(sizeof(struct conncache), 1); + if(!c) + return NULL; + + c->connects = calloc(sizeof(struct connectdata *), default_amount); + if(!c->connects) { + free(c); + return NULL; + } + + c->num = default_amount; + + return c; +} + +/* Change number of entries of a connection cache */ +CURLcode Curl_ch_connc(struct SessionHandle *data, + struct conncache *c, + long newamount) +{ + long i; + struct connectdata **newptr; + + if(newamount < 1) + newamount = 1; /* we better have at least one entry */ + + if(!c) { + /* we get a NULL pointer passed in as connection cache, which means that + there is no cache created for this SessionHandle just yet, we create a + brand new with the requested size. + */ + data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, newamount); + if(!data->state.connc) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; + } + + if(newamount < c->num) { + /* Since this number is *decreased* from the existing number, we must + close the possibly open connections that live on the indexes that + are being removed! + + NOTE: for conncache_multi cases we must make sure that we only + close handles not in use. + */ + for(i=newamount; i< c->num; i++) + Curl_disconnect(c->connects[i]); + + /* If the most recent connection is no longer valid, mark it + invalid. */ + if(data->state.lastconnect <= newamount) + data->state.lastconnect = -1; + } + if(newamount > 0) { + newptr= (struct connectdata **) + realloc(c->connects, sizeof(struct connectdata *) * newamount); + if(!newptr) + /* we closed a few connections in vain, but so what? */ + return CURLE_OUT_OF_MEMORY; + + /* nullify the newly added pointers */ + for(i=c->num; iconnects = newptr; + c->num = newamount; + } + /* we no longer support less than 1 as size for the connection cache, and + I'm not sure it ever worked to set it to zero */ + return CURLE_OK; +} + +/* Free a connection cache. This is called from Curl_close() and + curl_multi_cleanup(). */ +void Curl_rm_connc(struct conncache *c) +{ + if(c->connects) { + int i; + for(i = 0; i < c->num; ++i) + conn_free(c->connects[i]); + + free(c->connects); + } + + free(c); +} + +/** + * Curl_open() + * + * @param curl is a pointer to a sessionhandle pointer that gets set by this + * function. + * @return CURLcode + */ + +CURLcode Curl_open(struct SessionHandle **curl) +{ + CURLcode res = CURLE_OK; + struct SessionHandle *data; + + /* Very simple start-up: alloc the struct, init it with zeroes and return */ + data = (struct SessionHandle *)calloc(1, sizeof(struct SessionHandle)); + if(!data) + /* this is a very serious error */ + return CURLE_OUT_OF_MEMORY; + + data->magic = CURLEASY_MAGIC_NUMBER; + +#ifdef USE_ARES + if(ARES_SUCCESS != ares_init(&data->state.areschannel)) { + free(data); + return CURLE_FAILED_INIT; + } + /* make sure that all other returns from this function should destroy the + ares channel before returning error! */ +#endif + + /* We do some initial setup here, all those fields that can't be just 0 */ + + data->state.headerbuff=(char*)malloc(HEADERSIZE); + if(!data->state.headerbuff) + res = CURLE_OUT_OF_MEMORY; + else { + data->state.headersize=HEADERSIZE; + + data->set.out = stdout; /* default output to stdout */ + data->set.in = stdin; /* default input from stdin */ + data->set.err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + data->set.fwrite = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + data->set.fread = (curl_read_callback)fread; + + /* conversion callbacks for non-ASCII hosts */ + data->set.convfromnetwork = (curl_conv_callback)ZERO_NULL; + data->set.convtonetwork = (curl_conv_callback)ZERO_NULL; + data->set.convfromutf8 = (curl_conv_callback)ZERO_NULL; + +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) + /* conversion descriptors for iconv calls */ + data->outbound_cd = (iconv_t)-1; + data->inbound_cd = (iconv_t)-1; + data->utf8_cd = (iconv_t)-1; +#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ + + data->set.infilesize = -1; /* we don't know any size */ + data->set.postfieldsize = -1; + data->set.maxredirs = -1; /* allow any amount by default */ + data->state.current_speed = -1; /* init to negative == impossible */ + + data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */ + data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + data->set.ftp_filemethod = FTPFILE_MULTICWD; + data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* make libcurl quiet by default: */ + data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + data->progress.flags |= PGRS_HIDE; + + /* Set the default size of the SSL session ID cache */ + data->set.ssl.numsessions = 5; + + data->set.proxyport = 1080; + data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */ + data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + + /* This no longer creates a connection cache here. It is instead made on + the first call to curl_easy_perform() or when the handle is added to a + multi stack. */ + + data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ + + /* most recent connection is not yet defined */ + data->state.lastconnect = -1; + + Curl_easy_initHandleData(data); + + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + data->set.ssl.verifypeer = TRUE; + data->set.ssl.verifyhost = 2; + data->set.ssl.sessionid = TRUE; /* session ID caching enabled by default */ +#ifdef CURL_CA_BUNDLE + /* This is our preferred CA cert bundle since install time */ + data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; +#endif + } + + if(res) { + ares_destroy(data->state.areschannel); + if(data->state.headerbuff) + free(data->state.headerbuff); + free(data); + data = NULL; + } + else + *curl = data; + + return res; +} + +CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + va_list param) +{ + char *argptr; + CURLcode result = CURLE_OK; + + switch(option) { + case CURLOPT_DNS_CACHE_TIMEOUT: + data->set.dns_cache_timeout = va_arg(param, int); + break; + case CURLOPT_DNS_USE_GLOBAL_CACHE: + { + int use_cache = va_arg(param, int); + if (use_cache) { + Curl_global_host_cache_init(); + } + + data->set.global_dns_cache = (bool)(0 != use_cache); + } + break; + case CURLOPT_SSL_CIPHER_LIST: + /* set a list of cipher we want to use in the SSL connection */ + data->set.ssl.cipher_list = va_arg(param, char *); + break; + + case CURLOPT_RANDOM_FILE: + /* + * This is the path name to a file that contains random data to seed + * the random SSL stuff with. The file is only used for reading. + */ + data->set.ssl.random_file = va_arg(param, char *); + break; + case CURLOPT_EGDSOCKET: + /* + * The Entropy Gathering Daemon socket pathname + */ + data->set.ssl.egdsocket = va_arg(param, char *); + break; + case CURLOPT_MAXCONNECTS: + /* + * Set the absolute number of maximum simultaneous alive connection that + * libcurl is allowed to have. + */ + result = Curl_ch_connc(data, data->state.connc, va_arg(param, long)); + break; + case CURLOPT_FORBID_REUSE: + /* + * When this transfer is done, it must not be left to be reused by a + * subsequent transfer but shall be closed immediately. + */ + data->set.reuse_forbid = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_FRESH_CONNECT: + /* + * This transfer shall not use a previously cached connection but + * should be made with a fresh new connect! + */ + data->set.reuse_fresh = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_VERBOSE: + /* + * Verbose means infof() calls that give a lot of information about + * the connection and transfer procedures as well as internal choices. + */ + data->set.verbose = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_HEADER: + /* + * Set to include the header in the general data output stream. + */ + data->set.include_header = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_NOPROGRESS: + /* + * Shut off the internal supported progress meter + */ + data->set.hide_progress = (bool)(0 != va_arg(param, long)); + if(data->set.hide_progress) + data->progress.flags |= PGRS_HIDE; + else + data->progress.flags &= ~PGRS_HIDE; + break; + case CURLOPT_NOBODY: + /* + * Do not include the body part in the output data stream. + */ + data->set.opt_no_body = (bool)(0 != va_arg(param, long)); + if(data->set.opt_no_body) + /* in HTTP lingo, this means using the HEAD request */ + data->set.httpreq = HTTPREQ_HEAD; + break; + case CURLOPT_FAILONERROR: + /* + * Don't output the >=300 error code HTML-page, but instead only + * return error. + */ + data->set.http_fail_on_error = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_UPLOAD: + case CURLOPT_PUT: + /* + * We want to sent data to the remote host. If this is HTTP, that equals + * using the PUT request. + */ + data->set.upload = (bool)(0 != va_arg(param, long)); + if(data->set.upload) + /* If this is HTTP, PUT is what's needed to "upload" */ + data->set.httpreq = HTTPREQ_PUT; + break; + case CURLOPT_FILETIME: + /* + * Try to get the file time of the remote document. The time will + * later (possibly) become available using curl_easy_getinfo(). + */ + data->set.get_filetime = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_FTP_CREATE_MISSING_DIRS: + /* + * An FTP option that modifies an upload to create missing directories on + * the server. + */ + data->set.ftp_create_missing_dirs = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_FTP_RESPONSE_TIMEOUT: + /* + * An FTP option that specifies how quickly an FTP response must be + * obtained before it is considered failure. + */ + data->set.ftp_response_timeout = va_arg( param , long ); + break; + case CURLOPT_FTPLISTONLY: + /* + * An FTP option that changes the command to one that asks for a list + * only, no file info details. + */ + data->set.ftp_list_only = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_FTPAPPEND: + /* + * We want to upload and append to an existing (FTP) file. + */ + data->set.ftp_append = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_FTP_FILEMETHOD: + /* + * How do access files over FTP. + */ + data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long); + break; + case CURLOPT_NETRC: + /* + * Parse the $HOME/.netrc file + */ + data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long); + break; + case CURLOPT_NETRC_FILE: + /* + * Use this file instead of the $HOME/.netrc file + */ + data->set.netrc_file = va_arg(param, char *); + break; + case CURLOPT_TRANSFERTEXT: + /* + * This option was previously named 'FTPASCII'. Renamed to work with + * more protocols than merely FTP. + * + * Transfer using ASCII (instead of BINARY). + */ + data->set.prefer_ascii = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_TIMECONDITION: + /* + * Set HTTP time condition. This must be one of the defines in the + * curl/curl.h header file. + */ + data->set.timecondition = (curl_TimeCond)va_arg(param, long); + break; + case CURLOPT_TIMEVALUE: + /* + * This is the value to compare with the remote document with the + * method set with CURLOPT_TIMECONDITION + */ + data->set.timevalue = (time_t)va_arg(param, long); + break; + case CURLOPT_SSLVERSION: + /* + * Set explicit SSL version to try to connect with, as some SSL + * implementations are lame. + */ + data->set.ssl.version = va_arg(param, long); + break; + +#ifndef CURL_DISABLE_HTTP + case CURLOPT_AUTOREFERER: + /* + * Switch on automatic referer that gets set if curl follows locations. + */ + data->set.http_auto_referer = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_ENCODING: + /* + * String to use at the value of Accept-Encoding header. + * + * 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 don't send an Accept-Encoding header + * and ignore an received Content-Encoding header. + * + */ + data->set.encoding = va_arg(param, char *); + if(data->set.encoding && !*data->set.encoding) + data->set.encoding = (char*)ALL_CONTENT_ENCODINGS; + break; + + case CURLOPT_FOLLOWLOCATION: + /* + * Follow Location: header hints on a HTTP-server. + */ + data->set.http_follow_location = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_UNRESTRICTED_AUTH: + /* + * Send authentication (user+password) when following locations, even when + * hostname changed. + */ + data->set.http_disable_hostname_check_before_authentication = + (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_MAXREDIRS: + /* + * The maximum amount of hops you allow curl to follow Location: + * headers. This should mostly be used to detect never-ending loops. + */ + data->set.maxredirs = va_arg(param, long); + break; + + case CURLOPT_POST: + /* Does this option serve a purpose anymore? Yes it does, when + CURLOPT_POSTFIELDS isn't used and the POST data is read off the + callback! */ + if(va_arg(param, long)) { + data->set.httpreq = HTTPREQ_POST; + data->set.opt_no_body = FALSE; /* this is implied */ + } + else + data->set.httpreq = HTTPREQ_GET; + break; + + case CURLOPT_POSTFIELDS: + /* + * A string with POST data. Makes curl HTTP POST. Even if it is NULL. + */ + data->set.postfields = va_arg(param, char *); + data->set.httpreq = HTTPREQ_POST; + break; + + case CURLOPT_POSTFIELDSIZE: + /* + * The size of the POSTFIELD data to prevent libcurl to do strlen() to + * figure it out. Enables binary posts. + */ + data->set.postfieldsize = va_arg(param, long); + break; + + case CURLOPT_POSTFIELDSIZE_LARGE: + /* + * The size of the POSTFIELD data to prevent libcurl to do strlen() to + * figure it out. Enables binary posts. + */ + data->set.postfieldsize = va_arg(param, curl_off_t); + break; + + case CURLOPT_HTTPPOST: + /* + * Set to make us do HTTP POST + */ + data->set.httppost = va_arg(param, struct curl_httppost *); + data->set.httpreq = HTTPREQ_POST_FORM; + data->set.opt_no_body = FALSE; /* this is implied */ + break; + + case CURLOPT_REFERER: + /* + * String to set in the HTTP Referer: field. + */ + if(data->change.referer_alloc) { + free(data->change.referer); + data->change.referer_alloc = FALSE; + } + data->set.set_referer = va_arg(param, char *); + data->change.referer = data->set.set_referer; + break; + + case CURLOPT_USERAGENT: + /* + * String to use in the HTTP User-Agent field + */ + data->set.useragent = va_arg(param, char *); + break; + + case CURLOPT_HTTPHEADER: + /* + * Set a list with HTTP headers to use (or replace internals with) + */ + data->set.headers = va_arg(param, struct curl_slist *); + break; + + case CURLOPT_HTTP200ALIASES: + /* + * Set a list of aliases for HTTP 200 in response header + */ + data->set.http200aliases = va_arg(param, struct curl_slist *); + break; + +#if !defined(CURL_DISABLE_COOKIES) + case CURLOPT_COOKIE: + /* + * Cookie string to send to the remote server in the request. + */ + data->set.cookie = va_arg(param, char *); + break; + + case CURLOPT_COOKIEFILE: + /* + * Set cookie file to read and parse. Can be used multiple times. + */ + argptr = (char *)va_arg(param, void *); + if(argptr) { + struct curl_slist *cl; + /* append the cookie file name to the list of file names, and deal with + them later */ + cl = curl_slist_append(data->change.cookielist, argptr); + + if(!cl) + return CURLE_OUT_OF_MEMORY; + + data->change.cookielist = cl; + } + break; + + case CURLOPT_COOKIEJAR: + /* + * Set cookie file name to dump all cookies to when we're done. + */ + data->set.cookiejar = (char *)va_arg(param, void *); + + /* + * Activate the cookie parser. This may or may not already + * have been made. + */ + data->cookies = Curl_cookie_init(data, NULL, data->cookies, + data->set.cookiesession); + break; + + case CURLOPT_COOKIESESSION: + /* + * Set this option to TRUE to start a new "cookie session". It will + * prevent the forthcoming read-cookies-from-file actions to accept + * cookies that are marked as being session cookies, as they belong to a + * previous session. + * + * In the original Netscape cookie spec, "session cookies" are cookies + * with no expire date set. RFC2109 describes the same action if no + * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds + * a 'Discard' action that can enforce the discard even for cookies that + * have a Max-Age. + * + * We run mostly with the original cookie spec, as hardly anyone implements + * anything else. + */ + data->set.cookiesession = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_COOKIELIST: + argptr = va_arg(param, char *); + + if(argptr == NULL) + break; + + if(strequal(argptr, "ALL")) { + /* clear all cookies */ + Curl_cookie_clearall(data->cookies); + break; + } + else if(strequal(argptr, "SESS")) { + /* clear session cookies */ + Curl_cookie_clearsess(data->cookies); + break; + } + + if(!data->cookies) + /* if cookie engine was not running, activate it */ + data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); + + argptr = strdup(argptr); + if(!argptr) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + if(checkprefix("Set-Cookie:", argptr)) + /* HTTP Header format line */ + Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL); + + else + /* Netscape format line */ + Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL); + + free(argptr); + break; +#endif /* CURL_DISABLE_COOKIES */ + + case CURLOPT_HTTPGET: + /* + * Set to force us do HTTP GET + */ + if(va_arg(param, long)) { + data->set.httpreq = HTTPREQ_GET; + data->set.upload = FALSE; /* switch off upload */ + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; + + case CURLOPT_HTTP_VERSION: + /* + * This sets a requested HTTP version to be used. The value is one of + * the listed enums in curl/curl.h. + */ + data->set.httpversion = va_arg(param, long); + break; + + case CURLOPT_HTTPPROXYTUNNEL: + /* + * Tunnel operations through the proxy instead of normal proxy use + */ + data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_CUSTOMREQUEST: + /* + * Set a custom string to use as request + */ + data->set.customrequest = va_arg(param, char *); + + /* we don't set + data->set.httpreq = HTTPREQ_CUSTOM; + here, we continue as if we were using the already set type + and this just changes the actual request keyword */ + break; + + case CURLOPT_PROXYPORT: + /* + * Explicitly set HTTP proxy port number. + */ + data->set.proxyport = va_arg(param, long); + break; + + case CURLOPT_HTTPAUTH: + /* + * Set HTTP Authentication type BITMASK. + */ + { + long auth = va_arg(param, long); + /* switch off bits we can't support */ +#ifndef USE_NTLM + auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ +#endif +#ifndef HAVE_GSSAPI + auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */ +#endif + if(!auth) + return CURLE_FAILED_INIT; /* no supported types left! */ + + data->set.httpauth = auth; + } + break; + + case CURLOPT_PROXYAUTH: + /* + * Set HTTP Authentication type BITMASK. + */ + { + long auth = va_arg(param, long); + /* switch off bits we can't support */ +#ifndef USE_NTLM + auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ +#endif +#ifndef HAVE_GSSAPI + auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */ +#endif + if(!auth) + return CURLE_FAILED_INIT; /* no supported types left! */ + + data->set.proxyauth = auth; + } + break; +#endif /* CURL_DISABLE_HTTP */ + + case CURLOPT_PROXY: + /* + * Set proxy server:port to use as HTTP proxy. + * + * If the proxy is set to "" 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 + * to decide for us. + */ + data->set.proxy = va_arg(param, char *); + break; + + case CURLOPT_WRITEHEADER: + /* + * Custom pointer to pass the header write callback function + */ + data->set.writeheader = (void *)va_arg(param, void *); + break; + case CURLOPT_ERRORBUFFER: + /* + * Error buffer provided by the caller to get the human readable + * error string in. + */ + data->set.errorbuffer = va_arg(param, char *); + break; + case CURLOPT_FILE: + /* + * FILE pointer to write to or include in the data write callback + */ + data->set.out = va_arg(param, FILE *); + break; + case CURLOPT_FTPPORT: + /* + * Use FTP PORT, this also specifies which IP address to use + */ + data->set.ftpport = va_arg(param, char *); + data->set.ftp_use_port = (bool)(NULL != data->set.ftpport); + break; + + case CURLOPT_FTP_USE_EPRT: + data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_USE_EPSV: + data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_SSL_CCC: + data->set.ftp_use_ccc = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_SKIP_PASV_IP: + /* + * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the + * bypass of the IP address in PASV responses. + */ + data->set.ftp_skip_ip = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_INFILE: + /* + * FILE pointer to read the file to be uploaded from. Or possibly + * used as argument to the read callback. + */ + data->set.in = va_arg(param, FILE *); + break; + case CURLOPT_INFILESIZE: + /* + * If known, this should inform curl about the file size of the + * to-be-uploaded file. + */ + data->set.infilesize = va_arg(param, long); + break; + case CURLOPT_INFILESIZE_LARGE: + /* + * If known, this should inform curl about the file size of the + * to-be-uploaded file. + */ + data->set.infilesize = va_arg(param, curl_off_t); + break; + case CURLOPT_LOW_SPEED_LIMIT: + /* + * The low speed limit that if transfers are below this for + * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. + */ + data->set.low_speed_limit=va_arg(param, long); + break; + case CURLOPT_MAX_SEND_SPEED_LARGE: + /* + * The max speed limit that sends transfer more than + * CURLOPT_MAX_SEND_PER_SECOND bytes per second the transfer is + * throttled.. + */ + data->set.max_send_speed=va_arg(param, curl_off_t); + break; + case CURLOPT_MAX_RECV_SPEED_LARGE: + /* + * The max speed limit that sends transfer more than + * CURLOPT_MAX_RECV_PER_SECOND bytes per second the transfer is + * throttled.. + */ + data->set.max_recv_speed=va_arg(param, curl_off_t); + break; + case CURLOPT_LOW_SPEED_TIME: + /* + * The low speed time that if transfers are below the set + * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. + */ + data->set.low_speed_time=va_arg(param, long); + break; + case CURLOPT_URL: + /* + * The URL to fetch. + */ + if(data->change.url_alloc) { + /* the already set URL is allocated, free it first! */ + free(data->change.url); + data->change.url_alloc=FALSE; + } + data->set.set_url = va_arg(param, char *); + data->change.url = data->set.set_url; + data->change.url_changed = TRUE; + break; + case CURLOPT_PORT: + /* + * The port number to use when getting the URL + */ + data->set.use_port = va_arg(param, long); + break; + case CURLOPT_TIMEOUT: + /* + * The maximum time you allow curl to use for a single transfer + * operation. + */ + data->set.timeout = va_arg(param, long); + break; + case CURLOPT_CONNECTTIMEOUT: + /* + * The maximum time you allow curl to use to connect. + */ + data->set.connecttimeout = va_arg(param, long); + break; + + case CURLOPT_USERPWD: + /* + * user:password to use in the operation + */ + data->set.userpwd = va_arg(param, char *); + break; + case CURLOPT_POSTQUOTE: + /* + * List of RAW FTP commands to use after a transfer + */ + data->set.postquote = va_arg(param, struct curl_slist *); + break; + case CURLOPT_PREQUOTE: + /* + * List of RAW FTP commands to use prior to RETR (Wesley Laxton) + */ + data->set.prequote = va_arg(param, struct curl_slist *); + break; + case CURLOPT_QUOTE: + /* + * List of RAW FTP commands to use before a transfer + */ + data->set.quote = va_arg(param, struct curl_slist *); + break; + case CURLOPT_PROGRESSFUNCTION: + /* + * Progress callback function + */ + data->set.fprogress = va_arg(param, curl_progress_callback); + if(data->set.fprogress) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ + + break; + case CURLOPT_PROGRESSDATA: + /* + * Custom client data to pass to the progress callback + */ + data->set.progress_client = va_arg(param, void *); + break; + case CURLOPT_PROXYUSERPWD: + /* + * user:password needed to use the proxy + */ + data->set.proxyuserpwd = va_arg(param, char *); + break; + case CURLOPT_RANGE: + /* + * What range of the file you want to transfer + */ + data->set.set_range = va_arg(param, char *); + break; + case CURLOPT_RESUME_FROM: + /* + * Resume transfer at the give file position + */ + data->set.set_resume_from = va_arg(param, long); + break; + case CURLOPT_RESUME_FROM_LARGE: + /* + * Resume transfer at the give file position + */ + data->set.set_resume_from = va_arg(param, curl_off_t); + break; + case CURLOPT_DEBUGFUNCTION: + /* + * stderr write callback. + */ + data->set.fdebug = va_arg(param, curl_debug_callback); + /* + * if the callback provided is NULL, it'll use the default callback + */ + break; + case CURLOPT_DEBUGDATA: + /* + * Set to a void * that should receive all error writes. This + * defaults to CURLOPT_STDERR for normal operations. + */ + data->set.debugdata = va_arg(param, void *); + break; + case CURLOPT_STDERR: + /* + * Set to a FILE * that should receive all error writes. This + * defaults to stderr for normal operations. + */ + data->set.err = va_arg(param, FILE *); + if(!data->set.err) + data->set.err = stderr; + break; + case CURLOPT_HEADERFUNCTION: + /* + * Set header write callback + */ + data->set.fwrite_header = va_arg(param, curl_write_callback); + break; + case CURLOPT_WRITEFUNCTION: + /* + * Set data write callback + */ + data->set.fwrite = va_arg(param, curl_write_callback); + if(!data->set.fwrite) + /* When set to NULL, reset to our internal default function */ + data->set.fwrite = (curl_write_callback)fwrite; + break; + case CURLOPT_READFUNCTION: + /* + * Read data callback + */ + data->set.fread = va_arg(param, curl_read_callback); + if(!data->set.fread) + /* When set to NULL, reset to our internal default function */ + data->set.fread = (curl_read_callback)fread; + break; + case CURLOPT_CONV_FROM_NETWORK_FUNCTION: + /* + * "Convert from network encoding" callback + */ + data->set.convfromnetwork = va_arg(param, curl_conv_callback); + break; + case CURLOPT_CONV_TO_NETWORK_FUNCTION: + /* + * "Convert to network encoding" callback + */ + data->set.convtonetwork = va_arg(param, curl_conv_callback); + break; + case CURLOPT_CONV_FROM_UTF8_FUNCTION: + /* + * "Convert from UTF-8 encoding" callback + */ + data->set.convfromutf8 = va_arg(param, curl_conv_callback); + break; + case CURLOPT_IOCTLFUNCTION: + /* + * I/O control callback. Might be NULL. + */ + data->set.ioctl = va_arg(param, curl_ioctl_callback); + break; + case CURLOPT_IOCTLDATA: + /* + * I/O control data pointer. Might be NULL. + */ + data->set.ioctl_client = va_arg(param, void *); + break; + case CURLOPT_SSLCERT: + /* + * String that holds file name of the SSL certificate to use + */ + data->set.cert = va_arg(param, char *); + break; + case CURLOPT_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use + */ + data->set.cert_type = va_arg(param, char *); + break; + case CURLOPT_SSLKEY: + /* + * String that holds file name of the SSL certificate to use + */ + data->set.key = va_arg(param, char *); + break; + case CURLOPT_SSLKEYTYPE: + /* + * String that holds file type of the SSL certificate to use + */ + data->set.key_type = va_arg(param, char *); + break; + case CURLOPT_SSLKEYPASSWD: + /* + * String that holds the SSL private key password. + */ + data->set.key_passwd = va_arg(param, char *); + break; + case CURLOPT_SSLENGINE: + /* + * String that holds the SSL crypto engine. + */ + argptr = va_arg(param, char *); + if (argptr && argptr[0]) + result = Curl_ssl_set_engine(data, argptr); + break; + + case CURLOPT_SSLENGINE_DEFAULT: + /* + * flag to set engine as default. + */ + result = Curl_ssl_set_engine_default(data); + break; + case CURLOPT_CRLF: + /* + * Kludgy option to enable CRLF conversions. Subject for removal. + */ + data->set.crlf = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_INTERFACE: + /* + * Set what interface or address/hostname to bind the socket to when + * performing an operation and thus what from-IP your connection will use. + */ + data->set.device = va_arg(param, char *); + break; + case CURLOPT_LOCALPORT: + /* + * Set what local port to bind the socket to when performing an operation. + */ + data->set.localport = (unsigned short) va_arg(param, long); + break; + case CURLOPT_LOCALPORTRANGE: + /* + * Set number of local ports to try, starting with CURLOPT_LOCALPORT. + */ + data->set.localportrange = (int) va_arg(param, long); + break; + case CURLOPT_KRB4LEVEL: + /* + * A string that defines the krb4 security level. + */ + data->set.krb4_level = va_arg(param, char *); + data->set.krb4 = (bool)(NULL != data->set.krb4_level); + break; + case CURLOPT_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying. + */ + data->set.ssl.verifypeer = va_arg(param, long); + break; + case CURLOPT_SSL_VERIFYHOST: + /* + * Enable verification of the CN contained in the peer certificate + */ + data->set.ssl.verifyhost = va_arg(param, long); + break; + case CURLOPT_SSL_CTX_FUNCTION: + /* + * Set a SSL_CTX callback + */ + data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); + break; + case CURLOPT_SSL_CTX_DATA: + /* + * Set a SSL_CTX callback parameter pointer + */ + data->set.ssl.fsslctxp = va_arg(param, void *); + break; + case CURLOPT_CAINFO: + /* + * Set CA info for SSL connection. Specify file name of the CA certificate + */ + data->set.ssl.CAfile = va_arg(param, char *); + break; + case CURLOPT_CAPATH: + /* + * Set CA path info for SSL connection. Specify directory name of the CA + * certificates which have been prepared using openssl c_rehash utility. + */ + /* This does not work on windows. */ + data->set.ssl.CApath = va_arg(param, char *); + break; + case CURLOPT_TELNETOPTIONS: + /* + * Set a linked list of telnet options + */ + data->set.telnet_options = va_arg(param, struct curl_slist *); + break; + + case CURLOPT_BUFFERSIZE: + /* + * The application kindly asks for a differently sized receive buffer. + * If it seems reasonable, we'll use it. + */ + data->set.buffer_size = va_arg(param, long); + + if((data->set.buffer_size> (BUFSIZE -1 )) || + (data->set.buffer_size < 1)) + data->set.buffer_size = 0; /* huge internal default */ + + break; + + case CURLOPT_NOSIGNAL: + /* + * The application asks not to set any signal() or alarm() handlers, + * even when using a timeout. + */ + data->set.no_signal = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_SHARE: + { + struct Curl_share *set; + set = va_arg(param, struct Curl_share *); + + /* disconnect from old share, if any */ + if(data->share) { + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + + if(data->dns.hostcachetype == HCACHE_SHARED) { + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } + + if(data->share->cookies == data->cookies) + data->cookies = NULL; + + data->share->dirty--; + + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + data->share = NULL; + } + + /* use new share if it set */ + data->share = set; + if(data->share) { + + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + + data->share->dirty++; + + if(data->share->hostcache) { + /* use shared host cache, first free the private one if any */ + if(data->dns.hostcachetype == HCACHE_PRIVATE) + Curl_hash_destroy(data->dns.hostcache); + + data->dns.hostcache = data->share->hostcache; + data->dns.hostcachetype = HCACHE_SHARED; + } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(data->share->cookies) { + /* use shared cookie list, first free own one if any */ + if (data->cookies) + Curl_cookie_cleanup(data->cookies); + data->cookies = data->share->cookies; + } +#endif /* CURL_DISABLE_HTTP */ + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + + } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + /* check cookie list is set */ + if(!data->cookies) + data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE ); +#endif /* CURL_DISABLE_HTTP */ + /* check for host cache not needed, + * it will be done by curl_easy_perform */ + } + break; + + case CURLOPT_PROXYTYPE: + /* + * Set proxy type. HTTP/SOCKS4/SOCKS5 + */ + data->set.proxytype = (curl_proxytype)va_arg(param, long); + break; + + case CURLOPT_PRIVATE: + /* + * Set private data pointer. + */ + data->set.private_data = va_arg(param, char *); + break; + + case CURLOPT_MAXFILESIZE: + /* + * Set the maximum size of a file to download. + */ + data->set.max_filesize = va_arg(param, long); + break; + + case CURLOPT_FTP_SSL: + /* + * Make FTP transfers attempt to use SSL/TLS. + */ + data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long); + break; + + case CURLOPT_FTPSSLAUTH: + /* + * Set a specific auth for FTP-SSL transfers. + */ + data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long); + break; + + case CURLOPT_IPRESOLVE: + data->set.ip_version = va_arg(param, long); + break; + + case CURLOPT_MAXFILESIZE_LARGE: + /* + * Set the maximum size of a file to download. + */ + data->set.max_filesize = va_arg(param, curl_off_t); + break; + + case CURLOPT_TCP_NODELAY: + /* + * Enable or disable TCP_NODELAY, which will disable/enable the Nagle + * algorithm + */ + data->set.tcp_nodelay = (bool)(0 != va_arg(param, long)); + break; + + /* + case CURLOPT_SOURCE_URL: + case CURLOPT_SOURCE_USERPWD: + case CURLOPT_SOURCE_QUOTE: + case CURLOPT_SOURCE_PREQUOTE: + case CURLOPT_SOURCE_POSTQUOTE: + These former 3rd party transfer options are deprecated */ + + case CURLOPT_FTP_ACCOUNT: + data->set.ftp_account = va_arg(param, char *); + break; + + case CURLOPT_IGNORE_CONTENT_LENGTH: + data->set.ignorecl = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_CONNECT_ONLY: + /* + * No data transfer, set up connection and let application use the socket + */ + data->set.connect_only = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_FTP_ALTERNATIVE_TO_USER: + data->set.ftp_alternative_to_user = va_arg(param, char *); + break; + + case CURLOPT_SOCKOPTFUNCTION: + /* + * socket callback function: called after socket() but before connect() + */ + data->set.fsockopt = va_arg(param, curl_sockopt_callback); + break; + + case CURLOPT_SOCKOPTDATA: + /* + * socket callback data pointer. Might be NULL. + */ + data->set.sockopt_client = va_arg(param, void *); + break; + + case CURLOPT_SSL_SESSIONID_CACHE: + data->set.ssl.sessionid = (bool)(0 != va_arg(param, long)); + break; + + case CURLOPT_SSH_AUTH_TYPES: + data->set.ssh_auth_types = va_arg(param, long); + break; + + case CURLOPT_SSH_PUBLIC_KEYFILE: + /* + * Use this file instead of the $HOME/.ssh/id_dsa.pub file + */ + data->set.ssh_public_key = va_arg(param, char *); + break; + + case CURLOPT_SSH_PRIVATE_KEYFILE: + /* + * Use this file instead of the $HOME/.ssh/id_dsa file + */ + data->set.ssh_private_key = va_arg(param, char *); + break; + + default: + /* unknown tag and its companion, just ignore: */ + result = CURLE_FAILED_INIT; /* correct this */ + break; + } + + return result; +} + +static void conn_free(struct connectdata *conn) +{ + if (!conn) + return; + + /* close possibly still open sockets */ + if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) + sclose(conn->sock[SECONDARYSOCKET]); + if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) + sclose(conn->sock[FIRSTSOCKET]); + + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); + Curl_safefree(conn->proxyuser); + Curl_safefree(conn->proxypasswd); + Curl_safefree(conn->allocptr.proxyuserpwd); + Curl_safefree(conn->allocptr.uagent); + Curl_safefree(conn->allocptr.userpwd); + Curl_safefree(conn->allocptr.accept_encoding); + Curl_safefree(conn->allocptr.rangeline); + Curl_safefree(conn->allocptr.ref); + Curl_safefree(conn->allocptr.host); + Curl_safefree(conn->allocptr.cookiehost); + Curl_safefree(conn->ip_addr_str); + Curl_safefree(conn->trailer); + Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ + + Curl_llist_destroy(conn->send_pipe, NULL); + Curl_llist_destroy(conn->recv_pipe, NULL); + + /* possible left-overs from the async name resolvers */ +#if defined(USE_ARES) + Curl_safefree(conn->async.hostname); + Curl_safefree(conn->async.os_specific); +#elif defined(CURLRES_THREADED) + Curl_destroy_thread_data(&conn->async); +#endif + + Curl_free_ssl_config(&conn->ssl_config); + + free(conn); /* free all the connection oriented data */ +} + +CURLcode Curl_disconnect(struct connectdata *conn) +{ + struct SessionHandle *data; + if(!conn) + return CURLE_OK; /* this is closed and fine already */ + data = conn->data; + + if(!data) { + DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n")); + return CURLE_OK; + } + +#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST) + /* scan for DNS cache entries still marked as in use */ + Curl_hash_apply(data->hostcache, + NULL, Curl_scan_cache_used); +#endif + + Curl_expire(data, 0); /* shut off timers */ + Curl_hostcache_prune(data); /* kill old DNS cache entries */ + + /* + * The range string is usually freed in curl_done(), but we might + * get here *instead* if we fail prematurely. Thus we need to be able + * to free this resource here as well. + */ + if(data->reqdata.rangestringalloc) { + free(data->reqdata.range); + data->reqdata.rangestringalloc = FALSE; + } + + if((conn->ntlm.state != NTLMSTATE_NONE) || + (conn->proxyntlm.state != NTLMSTATE_NONE)) { + /* Authentication data is a mix of connection-related and sessionhandle- + related stuff. NTLM is connection-related so when we close the shop + we shall forget. */ + data->state.authhost.done = FALSE; + data->state.authhost.picked = + data->state.authhost.want; + + data->state.authproxy.done = FALSE; + data->state.authproxy.picked = + data->state.authproxy.want; + + data->state.authproblem = FALSE; + + Curl_ntlm_cleanup(conn); + } + + if(conn->curl_disconnect) + /* This is set if protocol-specific cleanups should be made */ + conn->curl_disconnect(conn); + + if(-1 != conn->connectindex) { + /* unlink ourselves! */ + infof(data, "Closing connection #%ld\n", conn->connectindex); + if(data->state.connc) + /* only clear the table entry if we still know in which cache we + used to be in */ + data->state.connc->connects[conn->connectindex] = NULL; + } + +#ifdef USE_LIBIDN + if(conn->host.encalloc) + idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed + with idn_free() since this was allocated + by libidn */ + if(conn->proxy.encalloc) + idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be + freed with idn_free() since this was + allocated by libidn */ +#endif + + Curl_ssl_close(conn); + + /* Indicate to all handles on the pipe that we're dead */ + if (IsPipeliningEnabled(data)) { + signalPipeClose(conn->send_pipe); + signalPipeClose(conn->recv_pipe); + } + + conn_free(conn); + + return CURLE_OK; +} + +/* + * This function should return TRUE if the socket is to be assumed to + * be dead. Most commonly this happens when the server has closed the + * connection due to inactivity. + */ +static bool SocketIsDead(curl_socket_t sock) +{ + int sval; + bool ret_val = TRUE; + + sval = Curl_select(sock, CURL_SOCKET_BAD, 0); + if(sval == 0) + /* timeout */ + ret_val = FALSE; + + return ret_val; +} + +static bool IsPipeliningPossible(struct SessionHandle *handle) +{ + if (handle->multi && Curl_multi_canPipeline(handle->multi) && + (handle->set.httpreq == HTTPREQ_GET || + handle->set.httpreq == HTTPREQ_HEAD) && + handle->set.httpversion != CURL_HTTP_VERSION_1_0) + return TRUE; + + return FALSE; +} + +static bool IsPipeliningEnabled(struct SessionHandle *handle) +{ + if (handle->multi && Curl_multi_canPipeline(handle->multi)) + return TRUE; + + return FALSE; +} + +void Curl_addHandleToPipeline(struct SessionHandle *data, + struct curl_llist *pipe) +{ +#ifdef CURLDEBUG + if(!IsPipeliningPossible(data)) { + /* when not pipelined, there MUST be no handle in the list already */ + if(pipe->head) + infof(data, "PIPE when no PIPE supposed!\n"); + } +#endif + Curl_llist_insert_next(pipe, pipe->tail, data); +} + + +int Curl_removeHandleFromPipeline(struct SessionHandle *handle, + struct curl_llist *pipe) +{ + struct curl_llist_element *curr; + + curr = pipe->head; + while (curr) { + if (curr->ptr == handle) { + Curl_llist_remove(pipe, curr, NULL); + return 1; /* we removed a handle */ + } + curr = curr->next; + } + + return 0; +} + +#if 0 /* this code is saved here as it is useful for debugging purposes */ +static void Curl_printPipeline(struct curl_llist *pipe) +{ + struct curl_llist_element *curr; + + curr = pipe->head; + while (curr) { + struct SessionHandle *data = (struct SessionHandle *) curr->ptr; + infof(data, "Handle in pipeline: %s\n", + data->reqdata.path); + curr = curr->next; + } +} +#endif + +bool Curl_isHandleAtHead(struct SessionHandle *handle, + struct curl_llist *pipe) +{ + struct curl_llist_element *curr = pipe->head; + if (curr) { + return (bool)(curr->ptr == handle); + } + + return FALSE; +} + +static void signalPipeClose(struct curl_llist *pipe) +{ + struct curl_llist_element *curr; + + curr = pipe->head; + while (curr) { + struct curl_llist_element *next = curr->next; + struct SessionHandle *data = (struct SessionHandle *) curr->ptr; + +#ifdef CURLDEBUG /* debug-only code */ + if(data->magic != CURLEASY_MAGIC_NUMBER) { + /* MAJOR BADNESS */ + fprintf(stderr, "signalPipeClose() found BAAD easy handle\n"); + } + else +#endif + + data->state.pipe_broke = TRUE; + Curl_llist_remove(pipe, curr, NULL); + curr = next; + } +} + + +/* + * 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. + */ +static bool +ConnectionExists(struct SessionHandle *data, + struct connectdata *needle, + struct connectdata **usethis) +{ + long i; + struct connectdata *check; + bool canPipeline = IsPipeliningPossible(data); + + for(i=0; i< data->state.connc->num; i++) { + bool match = FALSE; + /* + * Note that if we use a HTTP proxy, we check connections to that + * proxy and not to the actual remote server. + */ + check = data->state.connc->connects[i]; + if(!check) + /* NULL pointer means not filled-in entry */ + continue; + + if (check->connectindex == -1) { + check->connectindex = i; /* Set this appropriately since it might have + been set to -1 when the easy was removed + from the multi */ + } + + infof(data, "Examining connection #%ld for reuse\n", check->connectindex); + + if(check->inuse && !canPipeline) { + /* can only happen within multi handles, and means that another easy + handle is using this connection */ + continue; + } + +#ifdef CURLRES_ASYNCH + /* ip_addr_str is NULL only if the resolving of the name hasn't completed + yet and until then we don't re-use this connection */ + if (!check->ip_addr_str) { + infof(data, + "Connection #%ld has not finished name resolve, can't reuse\n", + check->connectindex); + continue; + } +#endif + + if (check->send_pipe->size + + check->recv_pipe->size >= MAX_PIPELINE_LENGTH) { + infof(data, "Connection #%ld has its pipeline full, can't reuse\n", + check->connectindex); + continue; + } + + if (data->state.is_in_pipeline && check->bits.close) { + /* Don't pick a connection that is going to be closed */ + infof(data, "Connection #%ld has been marked for close, can't reuse\n", + check->connectindex); + continue; + } + + if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL)) + /* don't do mixed SSL and non-SSL connections */ + continue; + + if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) { + /* The requested connection does not use a HTTP proxy or it + uses SSL. */ + + if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy) + /* we don't do SSL but the cached connection has a proxy, + then don't match this */ + continue; + + if(strequal(needle->protostr, check->protostr) && + strequal(needle->host.name, check->host.name) && + (needle->remote_port == check->remote_port) ) { + if(needle->protocol & PROT_SSL) { + /* This is SSL, verify that we're using the same + ssl options as well */ + if(!Curl_ssl_config_matches(&needle->ssl_config, + &check->ssl_config)) { + infof(data, + "Connection #%ld has different SSL parameters, " + "can't reuse\n", + check->connectindex ); + continue; + } + } + if((needle->protocol & PROT_FTP) || + ((needle->protocol & PROT_HTTP) && + (data->state.authhost.want==CURLAUTH_NTLM))) { + /* This is FTP or HTTP+NTLM, verify that we're using the same name + and password as well */ + if(!strequal(needle->user, check->user) || + !strequal(needle->passwd, check->passwd)) { + /* one of them was different */ + continue; + } + } + match = TRUE; + } + } + else { /* The requested needle connection is using a proxy, + is the checked one using the same? */ + if(check->bits.httpproxy && + strequal(needle->proxy.name, check->proxy.name) && + needle->port == check->port) { + /* This is the same proxy connection, use it! */ + match = TRUE; + } + } + + if(match) { + if (!IsPipeliningEnabled(data)) { + /* The check for a dead socket makes sense only in the + non-pipelining case */ + bool dead = SocketIsDead(check->sock[FIRSTSOCKET]); + if(dead) { + check->data = data; + infof(data, "Connection #%d seems to be dead!\n", i); + + Curl_disconnect(check); /* disconnect resources */ + data->state.connc->connects[i]=NULL; /* nothing here */ + + return FALSE; + } + } + + check->inuse = TRUE; /* mark this as being in use so that no other + handle in a multi stack may nick it */ + + if (canPipeline) { + /* Mark the connection as being in a pipeline */ + check->is_in_pipeline = TRUE; + } + + check->connectindex = i; /* Set this appropriately since it might have + been set to -1 when the easy was removed + from the multi */ + *usethis = check; + return TRUE; /* yes, we found one to use! */ + } + } + + return FALSE; /* no matching connecting exists */ +} + + + +/* + * This function frees/closes a connection in the connection cache. This + * should take the previously set policy into account when deciding which + * of the connections to kill. + */ +static long +ConnectionKillOne(struct SessionHandle *data) +{ + long i; + struct connectdata *conn; + long highscore=-1; + long connindex=-1; + long score; + struct timeval now; + + now = Curl_tvnow(); + + for(i=0; data->state.connc && (i< data->state.connc->num); i++) { + conn = data->state.connc->connects[i]; + + if(!conn || conn->inuse) + continue; + + /* Set higher score for the age passed since the connection was used */ + score = Curl_tvdiff(now, conn->now); + + if(score > highscore) { + highscore = score; + connindex = i; + } + } + if(connindex >= 0) { + /* Set the connection's owner correctly */ + conn = data->state.connc->connects[connindex]; + conn->data = data; + + /* the winner gets the honour of being disconnected */ + (void)Curl_disconnect(conn); + + /* clean the array entry */ + data->state.connc->connects[connindex] = NULL; + } + + return connindex; /* return the available index or -1 */ +} + +/* this connection can now be marked 'idle' */ +static void +ConnectionDone(struct connectdata *conn) +{ + conn->inuse = FALSE; + if (!conn->send_pipe && !conn->recv_pipe) + conn->is_in_pipeline = FALSE; +} + +/* + * The given input connection struct pointer is to be stored. If the "cache" + * is already full, we must clean out the most suitable using the previously + * set policy. + * + * The given connection should be unique. That must've been checked prior to + * this call. + */ +static long +ConnectionStore(struct SessionHandle *data, + struct connectdata *conn) +{ + long i; + for(i=0; i< data->state.connc->num; i++) { + if(!data->state.connc->connects[i]) + break; + } + if(i == data->state.connc->num) { + /* there was no room available, kill one */ + i = ConnectionKillOne(data); + if(-1 != i) + infof(data, "Connection (#%d) was killed to make room (holds %d)\n", + i, data->state.connc->num); + else + infof(data, "This connection did not fit in the connection cache\n"); + } + + conn->connectindex = i; /* Make the child know where the pointer to this + particular data is stored. But note that this -1 + if this is not within the cache and this is + probably not checked for everywhere (yet). */ + conn->inuse = TRUE; + if(-1 != i) { + /* Only do this if a true index was returned, if -1 was returned there + is no room in the cache for an unknown reason and we cannot store + this there. + + TODO: make sure we really can work with more handles than positions in + the cache, or possibly we should (allow to automatically) resize the + connection cache when we add more easy handles to a multi handle! + */ + data->state.connc->connects[i] = conn; /* fill in this */ + conn->data = data; + } + + return i; +} + +static CURLcode ConnectPlease(struct SessionHandle *data, + struct connectdata *conn, + struct Curl_dns_entry *hostaddr, + bool *connected) +{ + CURLcode result; + Curl_addrinfo *addr; + char *hostname = conn->bits.httpproxy?conn->proxy.name:conn->host.name; + + infof(data, "About to connect() to %s%s port %d (#%d)\n", + conn->bits.httpproxy?"proxy ":"", + hostname, conn->port, conn->connectindex); + + /************************************************************* + * Connect to server/proxy + *************************************************************/ + result= Curl_connecthost(conn, + hostaddr, + &conn->sock[FIRSTSOCKET], + &addr, + connected); + if(CURLE_OK == result) { + /* All is cool, then we store the current information */ + conn->dns_entry = hostaddr; + conn->ip_addr = addr; + + Curl_store_ip_addr(conn); + + switch(data->set.proxytype) { + case CURLPROXY_SOCKS5: + result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, conn); + break; + case CURLPROXY_HTTP: + /* do nothing here. handled later. */ + break; + case CURLPROXY_SOCKS4: + result = Curl_SOCKS4(conn->proxyuser, conn); + break; + default: + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + break; + } + } + + return result; +} + +/* + * verboseconnect() displays verbose information after a connect + */ +static void verboseconnect(struct connectdata *conn) +{ + infof(conn->data, "Connected to %s (%s) port %d (#%d)\n", + conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname, + conn->ip_addr_str, conn->port, conn->connectindex); +} + +int Curl_protocol_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + if(conn->curl_proto_getsock) + return conn->curl_proto_getsock(conn, socks, numsocks); + return GETSOCK_BLANK; +} + +int Curl_doing_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + if(conn && conn->curl_doing_getsock) + return conn->curl_doing_getsock(conn, socks, numsocks); + return GETSOCK_BLANK; +} + +/* + * We are doing protocol-specific connecting and this is being called over and + * over from the multi interface until the connection phase is done on + * protocol layer. + */ + +CURLcode Curl_protocol_connecting(struct connectdata *conn, + bool *done) +{ + CURLcode result=CURLE_OK; + + if(conn && conn->curl_connecting) { + *done = FALSE; + result = conn->curl_connecting(conn, done); + } + else + *done = TRUE; + + return result; +} + +/* + * We are DOING this is being called over and over from the multi interface + * until the DOING phase is done on protocol layer. + */ + +CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done) +{ + CURLcode result=CURLE_OK; + + if(conn && conn->curl_doing) { + *done = FALSE; + result = conn->curl_doing(conn, done); + } + else + *done = TRUE; + + return result; +} + +/* + * We have discovered that the TCP connection has been successful, we can now + * proceed with some action. + * + */ +CURLcode Curl_protocol_connect(struct connectdata *conn, + bool *protocol_done) +{ + CURLcode result=CURLE_OK; + struct SessionHandle *data = conn->data; + + *protocol_done = FALSE; + + if(conn->bits.tcpconnect && 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 don't know if the protocol is actually done. + + Unless this protocol doesn't have any protocol-connect callback, as + then we know we're done. */ + if(!conn->curl_connecting) + *protocol_done = TRUE; + + return CURLE_OK; + } + + if(!conn->bits.tcpconnect) { + + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + + if(data->set.verbose) + verboseconnect(conn); + } + + if(!conn->bits.protoconnstart) { + if(conn->curl_connect) { + /* is there a protocol-specific connect() procedure? */ + + /* Set start time here for timeout purposes in the connect procedure, it + is later set again for the progress meter purpose */ + conn->now = Curl_tvnow(); + + /* Call the protocol-specific connect function */ + result = conn->curl_connect(conn, protocol_done); + } + else + *protocol_done = TRUE; + + /* it has started, possibly even completed but that knowledge isn't stored + in this bit! */ + if (!result) + conn->bits.protoconnstart = TRUE; + } + + return result; /* pass back status */ +} + +/* + * Helpers for IDNA convertions. + */ +#ifdef USE_LIBIDN +static bool is_ASCII_name(const char *hostname) +{ + const unsigned char *ch = (const unsigned char*)hostname; + + while (*ch) { + if (*ch++ & 0x80) + return FALSE; + } + return TRUE; +} + +/* + * Check if characters in hostname is allowed in Top Level Domain. + */ +static bool tld_check_name(struct SessionHandle *data, + const char *ace_hostname) +{ + size_t err_pos; + char *uc_name = NULL; + int rc; + + /* Convert (and downcase) ACE-name back into locale's character set */ + rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0); + if (rc != IDNA_SUCCESS) + return (FALSE); + + rc = tld_check_lz(uc_name, &err_pos, NULL); + if (rc == TLD_INVALID) + infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n", +#ifdef HAVE_TLD_STRERROR + tld_strerror((Tld_rc)rc), +#else + "", +#endif + err_pos, uc_name[err_pos], + uc_name[err_pos] & 255); + else if (rc != TLD_SUCCESS) + infof(data, "WARNING: TLD check for %s failed; %s\n", + uc_name, +#ifdef HAVE_TLD_STRERROR + tld_strerror((Tld_rc)rc) +#else + "" +#endif + ); + if (uc_name) + idn_free(uc_name); + return (bool)(rc == TLD_SUCCESS); +} +#endif + +static void fix_hostname(struct SessionHandle *data, + struct connectdata *conn, struct hostname *host) +{ + /* set the name we use to display the host name */ + host->dispname = host->name; + +#ifdef USE_LIBIDN + /************************************************************* + * Check name for non-ASCII and convert hostname to ACE form. + *************************************************************/ + if (!is_ASCII_name(host->name) && + stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { + char *ace_hostname = NULL; + int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); + infof (data, "Input domain encoded as `%s'\n", + stringprep_locale_charset ()); + if (rc != IDNA_SUCCESS) + infof(data, "Failed to convert %s to ACE; %s\n", + host->name, Curl_idn_strerror(conn,rc)); + else { + /* tld_check_name() displays a warning if the host name contains + "illegal" characters for this TLD */ + (void)tld_check_name(data, ace_hostname); + + host->encalloc = ace_hostname; + /* change the name pointer to point to the encoded hostname */ + host->name = host->encalloc; + } + } +#else + (void)data; /* never used */ + (void)conn; /* never used */ +#endif +} + +/* + * Parse URL and fill in the relevant members of the connection struct. + */ +static CURLcode ParseURLAndFillConnection(struct SessionHandle *data, + struct connectdata *conn) +{ + char *at; + char *tmp; + + char *path = data->reqdata.path; + + /************************************************************* + * Parse the URL. + * + * We need to parse the url even when using the proxy, because we will need + * the hostname and port in case we are trying to SSL connect through the + * proxy -- and we don't know if we will need to use SSL until we parse the + * url ... + ************************************************************/ + if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]", + conn->protostr, + path)) && strequal(conn->protostr, "file")) { + if(path[0] == '/' && path[1] == '/') { + /* Allow omitted hostname (e.g. file:/). This is not strictly + * speaking a valid file: URL by RFC 1738, but treating file:/ as + * file://localhost/ is similar to how other schemes treat missing + * hostnames. See RFC 1808. */ + + /* This cannot be done with strcpy() in a portable manner, since the + memory areas overlap! */ + memmove(path, path + 2, strlen(path + 2)+1); + } + /* + * we deal with file:/// differently since it supports no + * hostname other than "localhost" and "127.0.0.1", which is unique among + * the URL protocols specified in RFC 1738 + */ + if(path[0] != '/') { + /* the URL included a host name, we ignore host names in file:// URLs + as the standards don't define what to do with them */ + char *ptr=strchr(path, '/'); + if(ptr) { + /* there was a slash present + + RFC1738 (section 3.1, page 5) says: + + The rest of the locator consists of data specific to the scheme, + and is known as the "url-path". It supplies the details of how the + specified resource can be accessed. Note that the "/" between the + host (or port) and the url-path is NOT part of the url-path. + + As most agents use file://localhost/foo to get '/foo' although the + slash preceding foo is a separator and not a slash for the path, + a URL as file://localhost//foo must be valid as well, to refer to + the same file with an absolute path. + */ + + if(ptr[1] && ('/' == ptr[1])) + /* if there was two slashes, we skip the first one as that is then + used truly as a separator */ + ptr++; + + /* This cannot be made with strcpy, as the memory chunks overlap! */ + memmove(path, ptr, strlen(ptr)+1); + } + } + + strcpy(conn->protostr, "file"); /* store protocol string lowercase */ + } + else { + /* clear path */ + path[0]=0; + + if (2 > sscanf(data->change.url, + "%15[^\n:]://%[^\n/]%[^\n]", + conn->protostr, + conn->host.name, path)) { + + /* + * The URL was badly formatted, let's try the browser-style _without_ + * protocol specified like 'http://'. + */ + if((1 > sscanf(data->change.url, "%[^\n/]%[^\n]", + conn->host.name, path)) ) { + /* + * We couldn't even get this format. + */ + failf(data, " malformed"); + return CURLE_URL_MALFORMAT; + } + + /* + * Since there was no protocol part specified, we guess what protocol it + * is based on the first letters of the server name. + */ + + /* Note: if you add a new protocol, please update the list in + * lib/version.c too! */ + + if(checkprefix("FTP.", conn->host.name)) + strcpy(conn->protostr, "ftp"); + else if (checkprefix("DICT.", conn->host.name)) + strcpy(conn->protostr, "DICT"); + else if (checkprefix("LDAP.", conn->host.name)) + strcpy(conn->protostr, "LDAP"); + else { + strcpy(conn->protostr, "http"); + } + + conn->protocol |= PROT_MISSING; /* not given in URL */ + } + } + + /* We search for '?' in the host name (but only on the right side of a + * @-letter to allow ?-letters in username and password) to handle things + * like http://example.com?param= (notice the missing '/'). + */ + at = strchr(conn->host.name, '@'); + if(at) + tmp = strchr(at+1, '?'); + else + tmp = strchr(conn->host.name, '?'); + + if(tmp) { + /* We must insert a slash before the '?'-letter in the URL. If the URL had + a slash after the '?', that is where the path currently begins and the + '?string' is still part of the host name. + + We must move the trailing part from the host name and put it first in + the path. And have it all prefixed with a slash. + */ + + size_t hostlen = strlen(tmp); + size_t pathlen = strlen(path); + + /* move the existing path plus the zero byte forward, to make room for + the host-name part */ + memmove(path+hostlen+1, path, pathlen+1); + + /* now copy the trailing host part in front of the existing path */ + memcpy(path+1, tmp, hostlen); + + path[0]='/'; /* prepend the missing slash */ + + *tmp=0; /* now cut off the hostname at the ? */ + } + else if(!path[0]) { + /* if there's no path set, use a single slash */ + strcpy(path, "/"); + } + + /* If the URL is malformatted (missing a '/' after hostname before path) we + * insert a slash here. The only letter except '/' we accept to start a path + * is '?'. + */ + if(path[0] == '?') { + /* We need this function to deal with overlapping memory areas. We know + that the memory area 'path' points to is 'urllen' bytes big and that + is bigger than the path. Use +1 to move the zero byte too. */ + memmove(&path[1], path, strlen(path)+1); + path[0] = '/'; + } + + /* + * So if the URL was A://B/C, + * conn->protostr is A + * conn->host.name is B + * data->reqdata.path is /C + */ + + return CURLE_OK; +} + +static void llist_dtor(void *user, void *element) +{ + (void)user; + (void)element; + /* Do nothing */ +} + + +/** + * CreateConnection() sets up a new connectdata struct, or re-uses an already + * 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 + * already resolved. + * + * @param data The sessionhandle pointer + * @param in_connect is set to the next connection data pointer + * @param addr is set to the new dns entry for this connection. If this + * connection is re-used it will be NULL. + * @param async is set TRUE/FALSE depending on the nature of this lookup + * @return CURLcode + * @see SetupConnection() + * + * *NOTE* this function assigns the conn->data pointer! + */ + +static CURLcode CreateConnection(struct SessionHandle *data, + struct connectdata **in_connect, + struct Curl_dns_entry **addr, + bool *async) +{ + + char *tmp; + CURLcode result=CURLE_OK; + struct connectdata *conn; + struct connectdata *conn_temp = NULL; + size_t urllen; + struct Curl_dns_entry *hostaddr; +#if defined(HAVE_ALARM) && !defined(USE_ARES) + unsigned int prev_alarm=0; +#endif + char endbracket; + char user[MAX_CURL_USER_LENGTH]; + char passwd[MAX_CURL_PASSWORD_LENGTH]; + int rc; + bool reuse; + char *proxy; + bool proxy_alloc = FALSE; + +#ifndef USE_ARES +#ifdef SIGALRM +#ifdef HAVE_SIGACTION + struct sigaction keep_sigact; /* store the old struct here */ + bool keep_copysig=FALSE; /* did copy it? */ +#else +#ifdef HAVE_SIGNAL + void (*keep_sigact)(int); /* store the old handler here */ +#endif /* HAVE_SIGNAL */ +#endif /* HAVE_SIGACTION */ +#endif /* SIGALRM */ +#endif /* USE_ARES */ + + *addr = NULL; /* nothing yet */ + *async = FALSE; + + /************************************************************* + * Check input data + *************************************************************/ + + if(!data->change.url) + return CURLE_URL_MALFORMAT; + + /* First, split up the current URL in parts so that we can use the + parts for checking against the already present connections. In order + to not have to modify everything at once, we allocate a temporary + connection data struct and fill in for comparison purposes. */ + + conn = (struct connectdata *)calloc(sizeof(struct connectdata), 1); + if(!conn) { + *in_connect = NULL; /* clear the pointer */ + return CURLE_OUT_OF_MEMORY; + } + /* We must set the return variable as soon as possible, so that our + parent can cleanup any possible allocs we may have done before + any failure */ + *in_connect = conn; + + /* and we setup a few fields in case we end up actually using this struct */ + + conn->data = data; /* Setup the association between this connection + and the SessionHandle */ + + conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->connectindex = -1; /* no index */ + + conn->bits.httpproxy = (bool)(data->set.proxy /* http proxy or not */ + && *data->set.proxy + && (data->set.proxytype == CURLPROXY_HTTP)); + proxy = data->set.proxy; /* if global proxy is set, this is it */ + + /* 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. */ + conn->bits.close = TRUE; + + conn->readchannel_inuse = FALSE; + conn->writechannel_inuse = FALSE; + + conn->read_pos = 0; + conn->buf_len = 0; + + /* Initialize the pipeline lists */ + conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); + conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); + + /* Store creation time to help future close decision making */ + conn->created = Curl_tvnow(); + + /* range status */ + data->reqdata.use_range = (bool)(NULL != data->set.set_range); + + data->reqdata.range = data->set.set_range; /* clone the range setting */ + data->reqdata.resume_from = data->set.set_resume_from; + + conn->bits.user_passwd = (bool)(NULL != data->set.userpwd); + conn->bits.proxy_user_passwd = (bool)(NULL != data->set.proxyuserpwd); + conn->bits.no_body = data->set.opt_no_body; + conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; + conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; + conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; + + /* This initing continues below, see the comment "Continue connectdata + * initialization here" */ + + /*********************************************************** + * We need to allocate memory to store the path in. We get the size of the + * full URL to be sure, and we need to make it at least 256 bytes since + * other parts of the code will rely on this fact + ***********************************************************/ +#define LEAST_PATH_ALLOC 256 + urllen=strlen(data->change.url); + if(urllen < LEAST_PATH_ALLOC) + urllen=LEAST_PATH_ALLOC; + + if (!data->set.source_url /* 3rd party FTP */ + && data->reqdata.pathbuffer) { + /* Free the old buffer */ + free(data->reqdata.pathbuffer); + } + + /* + * We malloc() the buffers below urllen+2 to make room for to possibilities: + * 1 - an extra terminating zero + * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used) + */ + + data->reqdata.pathbuffer=(char *)malloc(urllen+2); + if(NULL == data->reqdata.pathbuffer) + return CURLE_OUT_OF_MEMORY; /* really bad error */ + data->reqdata.path = data->reqdata.pathbuffer; + + conn->host.rawalloc=(char *)malloc(urllen+2); + if(NULL == conn->host.rawalloc) + return CURLE_OUT_OF_MEMORY; + + conn->host.name = conn->host.rawalloc; + conn->host.name[0] = 0; + + result = ParseURLAndFillConnection(data, conn); + if (result != CURLE_OK) { + return result; + } + + /************************************************************* + * Take care of proxy authentication stuff + *************************************************************/ + if(conn->bits.proxy_user_passwd) { + char proxyuser[MAX_CURL_USER_LENGTH]=""; + char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; + + sscanf(data->set.proxyuserpwd, + "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" + "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", + proxyuser, proxypasswd); + + conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); + if(!conn->proxyuser) + return CURLE_OUT_OF_MEMORY; + + conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); + if(!conn->proxypasswd) + return CURLE_OUT_OF_MEMORY; + } + +#ifndef CURL_DISABLE_HTTP + /************************************************************* + * Detect what (if any) proxy to use + *************************************************************/ + if(!conn->bits.httpproxy) { + /* If proxy was not specified, we check for default proxy environment + * variables, to enable i.e Lynx compliance: + * + * http_proxy=http://some.server.dom:port/ + * https_proxy=http://some.server.dom:port/ + * ftp_proxy=http://some.server.dom:port/ + * no_proxy=domain1.dom,host.domain2.dom + * (a comma-separated list of hosts which should + * not be proxied, or an asterisk to override + * all proxy variables) + * all_proxy=http://some.server.dom:port/ + * (seems to exist for the CERN www lib. Probably + * the first to check for.) + * + * For compatibility, the all-uppercase versions of these variables are + * checked if the lowercase versions don't exist. + */ + char *no_proxy=NULL; + char *no_proxy_tok_buf; + char proxy_env[128]; + + no_proxy=curl_getenv("no_proxy"); + if(!no_proxy) + no_proxy=curl_getenv("NO_PROXY"); + + if(!no_proxy || !strequal("*", no_proxy)) { + /* NO_PROXY wasn't specified or it wasn't just an asterisk */ + char *nope; + + nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL; + while(nope) { + size_t namelen; + char *endptr = strchr(conn->host.name, ':'); + if(endptr) + namelen=endptr-conn->host.name; + else + namelen=strlen(conn->host.name); + + if(strlen(nope) <= namelen) { + char *checkn= + conn->host.name + namelen - strlen(nope); + if(checkprefix(nope, checkn)) { + /* no proxy for this host! */ + break; + } + } + nope=strtok_r(NULL, ", ", &no_proxy_tok_buf); + } + if(!nope) { + /* It was not listed as without proxy */ + char *protop = conn->protostr; + char *envp = proxy_env; + char *prox; + + /* Now, build _proxy and check for such a one to use */ + while(*protop) + *envp++ = (char)tolower((int)*protop++); + + /* append _proxy */ + strcpy(envp, "_proxy"); + + /* read the protocol proxy: */ + prox=curl_getenv(proxy_env); + + /* + * We don't try the uppercase version of HTTP_PROXY because of + * security reasons: + * + * When curl is used in a webserver application + * environment (cgi or php), this environment variable can + * be controlled by the web server user by setting the + * http header 'Proxy:' to some value. + * + * This can cause 'internal' http/ftp requests to be + * arbitrarily redirected by any external attacker. + */ + if(!prox && !strequal("http_proxy", proxy_env)) { + /* There was no lowercase variable, try the uppercase version: */ + for(envp = proxy_env; *envp; envp++) + *envp = (char)toupper((int)*envp); + prox=curl_getenv(proxy_env); + } + + if(prox && *prox) { /* don't count "" strings */ + proxy = prox; /* use this */ + } + else { + proxy = curl_getenv("all_proxy"); /* default proxy to use */ + if(!proxy) + proxy=curl_getenv("ALL_PROXY"); + } + + if(proxy && *proxy) { + long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); + /* force this to become HTTP */ + conn->protocol = PROT_HTTP | bits; + + proxy_alloc=TRUE; /* this needs to be freed later */ + conn->bits.httpproxy = TRUE; + } + } /* if (!nope) - it wasn't specified non-proxy */ + } /* NO_PROXY wasn't specified or '*' */ + if(no_proxy) + free(no_proxy); + } /* if not using proxy */ +#endif /* CURL_DISABLE_HTTP */ + + /************************************************************* + * No protocol part in URL was used, add it! + *************************************************************/ + if(conn->protocol&PROT_MISSING) { + /* We're guessing prefixes here and if we're told to use a proxy or if + we're gonna follow a Location: later or... then we need the protocol + part added so that we have a valid URL. */ + char *reurl; + + reurl = aprintf("%s://%s", conn->protostr, data->change.url); + + if(!reurl) + return CURLE_OUT_OF_MEMORY; + + data->change.url = reurl; + data->change.url_alloc = TRUE; /* free this later */ + conn->protocol &= ~PROT_MISSING; /* switch that one off again */ + } + +#ifndef CURL_DISABLE_HTTP + /************************************************************ + * RESUME on a HTTP page is a tricky business. First, let's just check that + * 'range' isn't used, then set the range parameter and leave the resume as + * it is to inform about this situation for later use. We will then + * "attempt" to resume, and if we're talking to a HTTP/1.1 (or later) + * server, we will get the document resumed. If we talk to a HTTP/1.0 + * server, we just fail since we can't rewind the file writing from within + * this function. + ***********************************************************/ + if(data->reqdata.resume_from) { + if(!data->reqdata.use_range) { + /* if it already was in use, we just skip this */ + data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", data->reqdata.resume_from); + if(!data->reqdata.range) + return CURLE_OUT_OF_MEMORY; + data->reqdata.rangestringalloc = TRUE; /* mark as allocated */ + data->reqdata.use_range = 1; /* switch on range usage */ + } + } +#endif + /************************************************************* + * Setup internals depending on protocol + *************************************************************/ + + conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ + + if (strequal(conn->protostr, "HTTP")) { +#ifndef CURL_DISABLE_HTTP + conn->port = PORT_HTTP; + conn->remote_port = PORT_HTTP; + conn->protocol |= PROT_HTTP; + conn->curl_do = Curl_http; + conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; + conn->curl_done = Curl_http_done; + conn->curl_connect = Curl_http_connect; +#else + failf(data, LIBCURL_NAME + " was built with HTTP disabled, http: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + else if (strequal(conn->protostr, "HTTPS")) { +#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + + conn->port = PORT_HTTPS; + conn->remote_port = PORT_HTTPS; + conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL; + + conn->curl_do = Curl_http; + conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; + conn->curl_done = Curl_http_done; + conn->curl_connect = Curl_http_connect; + conn->curl_connecting = Curl_https_connecting; + conn->curl_proto_getsock = Curl_https_getsock; + +#else /* USE_SSL */ + failf(data, LIBCURL_NAME + " was built with SSL disabled, https: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif /* !USE_SSL */ + } + else if(strequal(conn->protostr, "FTP") || + strequal(conn->protostr, "FTPS")) { + +#ifndef CURL_DISABLE_FTP + char *type; + int port = PORT_FTP; + + if(strequal(conn->protostr, "FTPS")) { +#ifdef USE_SSL + conn->protocol |= PROT_FTPS|PROT_SSL; + conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */ + port = PORT_FTPS; +#else + failf(data, LIBCURL_NAME + " was built with SSL disabled, ftps: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif /* !USE_SSL */ + } + + conn->port = port; + conn->remote_port = (unsigned short)port; + conn->protocol |= PROT_FTP; + + if(proxy && *proxy && !data->set.tunnel_thru_httpproxy) { + /* Unless we have asked to tunnel ftp operations through the proxy, we + switch and use HTTP operations only */ +#ifndef CURL_DISABLE_HTTP + conn->curl_do = Curl_http; + conn->curl_done = Curl_http_done; + conn->protocol = PROT_HTTP; /* switch to HTTP */ +#else + failf(data, "FTP over http proxy requires HTTP support built-in!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + else { + conn->curl_do = Curl_ftp; + conn->curl_do_more = Curl_ftp_nextconnect; + conn->curl_done = Curl_ftp_done; + conn->curl_connect = Curl_ftp_connect; + conn->curl_connecting = Curl_ftp_multi_statemach; + conn->curl_doing = Curl_ftp_doing; + conn->curl_proto_getsock = Curl_ftp_getsock; + conn->curl_doing_getsock = Curl_ftp_getsock; + conn->curl_disconnect = Curl_ftp_disconnect; + } + + data->reqdata.path++; /* don't include the initial slash */ + + /* FTP URLs support an extension like ";type=" that + * we'll try to get now! */ + type=strstr(data->reqdata.path, ";type="); + if(!type) { + type=strstr(conn->host.rawalloc, ";type="); + } + if(type) { + char command; + *type=0; /* it was in the middle of the hostname */ + command = (char)toupper((int)type[6]); + switch(command) { + case 'A': /* ASCII mode */ + data->set.prefer_ascii = TRUE; + break; + case 'D': /* directory mode */ + data->set.ftp_list_only = TRUE; + break; + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->set.prefer_ascii = FALSE; + break; + } + } +#else /* CURL_DISABLE_FTP */ + failf(data, LIBCURL_NAME + " was built with FTP disabled, ftp/ftps: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + else if(strequal(conn->protostr, "TELNET")) { +#ifndef CURL_DISABLE_TELNET + /* telnet testing factory */ + conn->protocol |= PROT_TELNET; + + conn->port = PORT_TELNET; + conn->remote_port = PORT_TELNET; + conn->curl_do = Curl_telnet; + conn->curl_done = Curl_telnet_done; +#else + failf(data, LIBCURL_NAME + " was built with TELNET disabled!"); +#endif + } + else if (strequal(conn->protostr, "DICT")) { +#ifndef CURL_DISABLE_DICT + conn->protocol |= PROT_DICT; + conn->port = PORT_DICT; + conn->remote_port = PORT_DICT; + conn->curl_do = Curl_dict; + /* no DICT-specific done */ + conn->curl_done = (Curl_done_func)ZERO_NULL; +#else + failf(data, LIBCURL_NAME + " was built with DICT disabled!"); +#endif + } + else if (strequal(conn->protostr, "LDAP")) { +#ifndef CURL_DISABLE_LDAP + conn->protocol |= PROT_LDAP; + conn->port = PORT_LDAP; + conn->remote_port = PORT_LDAP; + conn->curl_do = Curl_ldap; + /* no LDAP-specific done */ + conn->curl_done = (Curl_done_func)ZERO_NULL; +#else + failf(data, LIBCURL_NAME + " was built with LDAP disabled!"); +#endif + } + else if (strequal(conn->protostr, "FILE")) { +#ifndef CURL_DISABLE_FILE + conn->protocol |= PROT_FILE; + + conn->curl_do = Curl_file; + conn->curl_done = Curl_file_done; + + /* anyway, this is supposed to be the connect function so we better + at least check that the file is present here! */ + result = Curl_file_connect(conn); + + /* Setup a "faked" transfer that'll do nothing */ + if(CURLE_OK == result) { + conn->data = data; + conn->bits.tcpconnect = TRUE; /* we are "connected */ + ConnectionStore(data, conn); + + result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ + -1, NULL); /* no upload */ + } + + return result; +#else + failf(data, LIBCURL_NAME + " was built with FILE disabled!"); +#endif + } + else if (strequal(conn->protostr, "TFTP")) { +#ifndef CURL_DISABLE_TFTP + char *type; + conn->socktype = SOCK_DGRAM; /* UDP datagram based */ + conn->protocol |= PROT_TFTP; + conn->port = PORT_TFTP; + conn->remote_port = PORT_TFTP; + conn->curl_connect = Curl_tftp_connect; + conn->curl_do = Curl_tftp; + conn->curl_done = Curl_tftp_done; + /* TFTP URLs support an extension like ";mode=" that + * we'll try to get now! */ + type=strstr(data->reqdata.path, ";mode="); + if(!type) { + type=strstr(conn->host.rawalloc, ";mode="); + } + if(type) { + char command; + *type=0; /* it was in the middle of the hostname */ + command = (char)toupper((int)type[6]); + switch(command) { + case 'A': /* ASCII mode */ + case 'N': /* NETASCII mode */ + data->set.prefer_ascii = TRUE; + break; + case 'O': /* octet mode */ + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->set.prefer_ascii = FALSE; + break; + } + } +#else + failf(data, LIBCURL_NAME + " was built with TFTP disabled!"); +#endif + } + else if (strequal(conn->protostr, "SCP")) { +#ifdef USE_LIBSSH2 + conn->port = PORT_SSH; + conn->remote_port = PORT_SSH; + conn->protocol = PROT_SCP; + conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */ + conn->curl_do = Curl_scp_do; + conn->curl_done = Curl_scp_done; + conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; +#else + failf(data, LIBCURL_NAME + " was built without LIBSSH2, scp: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + else if (strequal(conn->protostr, "SFTP")) { +#ifdef USE_LIBSSH2 + conn->port = PORT_SSH; + conn->remote_port = PORT_SSH; + conn->protocol = PROT_SFTP; + conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */ + conn->curl_do = Curl_sftp_do; + conn->curl_done = Curl_sftp_done; + conn->curl_do_more = (Curl_do_more_func)NULL; +#else + failf(data, LIBCURL_NAME + " was built without LIBSSH2, scp: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; +#endif +} +else { + /* We fell through all checks and thus we don't support the specified + protocol */ + failf(data, "Unsupported protocol: %s", conn->protostr); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + if(proxy && *proxy) { + /* If this is supposed to use a proxy, we need to figure out the proxy + host name name, so that we can re-use an existing connection + that may exist registered to the same proxy host. */ + + char *prox_portno; + char *endofprot; + + /* We need to make a duplicate of the proxy so that we can modify the + string safely. If 'proxy_alloc' is TRUE, the string is already + allocated and we can treat it as duplicated. */ + char *proxydup=proxy_alloc?proxy:strdup(proxy); + + /* We use 'proxyptr' to point to the proxy name from now on... */ + char *proxyptr=proxydup; + char *portptr; + char *atsign; + + if(NULL == proxydup) { + failf(data, "memory shortage"); + return CURLE_OUT_OF_MEMORY; + } + + /* We do the proxy host string parsing here. We want the host name and the + * port name. Accept a protocol:// prefix, even though it should just be + * ignored. + */ + + /* Skip the protocol part if present */ + endofprot=strstr(proxyptr, "://"); + if(endofprot) + proxyptr = endofprot+3; + + /* Is there a username and password given in this proxy url? */ + atsign = strchr(proxyptr, '@'); + if(atsign) { + char proxyuser[MAX_CURL_USER_LENGTH]; + char proxypasswd[MAX_CURL_PASSWORD_LENGTH]; + proxypasswd[0] = 0; + + if(1 <= sscanf(proxyptr, + "%" MAX_CURL_USER_LENGTH_TXT"[^:]:" + "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", + proxyuser, proxypasswd)) { + CURLcode res = CURLE_OK; + + /* found user and password, rip them out. note that we are + unescaping them, as there is otherwise no way to have a + username or password with reserved characters like ':' in + them. */ + Curl_safefree(conn->proxyuser); + conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); + + if(!conn->proxyuser) + res = CURLE_OUT_OF_MEMORY; + else { + Curl_safefree(conn->proxypasswd); + conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); + + if(!conn->proxypasswd) + res = CURLE_OUT_OF_MEMORY; + } + + if(CURLE_OK == res) { + conn->bits.proxy_user_passwd = TRUE; /* enable it */ + atsign = strdup(atsign+1); /* the right side of the @-letter */ + + if(atsign) { + free(proxydup); /* free the former proxy string */ + proxydup = proxyptr = atsign; /* now use this instead */ + } + else + res = CURLE_OUT_OF_MEMORY; + } + + if(res) { + free(proxydup); /* free the allocated proxy string */ + return res; + } + } + } + + /* start scanning for port number at this point */ + portptr = proxyptr; + + /* detect and extract RFC2732-style IPv6-addresses */ + if(*proxyptr == '[') { + char *ptr = ++proxyptr; /* advance beyond the initial bracket */ + while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':'))) + ptr++; + if(*ptr == ']') { + /* yeps, it ended nicely with a bracket as well */ + *ptr = 0; + portptr = ptr+1; + } + /* Note that if this didn't end with a bracket, we still advanced the + * proxyptr first, but I can't see anything wrong with that as no host + * name nor a numeric can legally start with a bracket. + */ + } + + /* Get port number off proxy.server.com:1080 */ + prox_portno = strchr(portptr, ':'); + if (prox_portno) { + *prox_portno = 0x0; /* cut off number from host name */ + prox_portno ++; + /* now set the local port number */ + conn->port = atoi(prox_portno); + } + else if(data->set.proxyport) { + /* None given in the proxy string, then get the default one if it is + given */ + conn->port = data->set.proxyport; + } + + /* now, clone the cleaned proxy host name */ + conn->proxy.rawalloc = strdup(proxyptr); + conn->proxy.name = conn->proxy.rawalloc; + + free(proxydup); /* free the duplicate pointer and not the modified */ + proxy = NULL; /* this may have just been freed */ + if(!conn->proxy.rawalloc) + return CURLE_OUT_OF_MEMORY; + } + + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->protocol&PROT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; + + /************************************************************* + * Take care of user and password authentication stuff + *************************************************************/ + + /* + * Inputs: data->set.userpwd (CURLOPT_USERPWD) + * data->set.fpasswd (CURLOPT_PASSWDFUNCTION) + * data->set.use_netrc (CURLOPT_NETRC) + * conn->host.name + * netrc file + * hard-coded defaults + * + * Outputs: (almost :- all currently undefined) + * conn->bits.user_passwd - non-zero if non-default passwords exist + * conn->user - non-zero length if defined + * conn->passwd - ditto + * conn->host.name - remove user name and password + */ + + /* At this point, we're hoping all the other special cases have + * been taken care of, so conn->host.name is at most + * [user[:password]]@]hostname + * + * We need somewhere to put the embedded details, so do that first. + */ + + user[0] =0; /* to make everything well-defined */ + passwd[0]=0; + + if (conn->protocol & (PROT_FTP|PROT_HTTP|PROT_SCP|PROT_SFTP)) { + /* This is a FTP, HTTP, SCP or SFTP URL, we will now try to extract the + * possible user+password pair in a string like: + * ftp://user:password@ftp.my.site:8021/README */ + char *ptr=strchr(conn->host.name, '@'); + char *userpass = conn->host.name; + if(ptr != NULL) { + /* there's a user+password given here, to the left of the @ */ + + conn->host.name = ++ptr; + + /* So the hostname is sane. Only bother interpreting the + * results if we could care. It could still be wasted + * work because it might be overtaken by the programmatically + * set user/passwd, but doing that first adds more cases here :-( + */ + + if (data->set.use_netrc != CURL_NETRC_REQUIRED) { + /* We could use the one in the URL */ + + conn->bits.user_passwd = 1; /* enable user+password */ + + if(*userpass != ':') { + /* the name is given, get user+password */ + sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:" + "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", + user, passwd); + } + else + /* no name given, get the password only */ + sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd); + + if(user[0]) { + char *newname=curl_easy_unescape(data, user, 0, NULL); + if(!newname) + return CURLE_OUT_OF_MEMORY; + if(strlen(newname) < sizeof(user)) + strcpy(user, newname); + + /* if the new name is longer than accepted, then just use + the unconverted name, it'll be wrong but what the heck */ + free(newname); + } + if (passwd[0]) { + /* we have a password found in the URL, decode it! */ + char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL); + if(!newpasswd) + return CURLE_OUT_OF_MEMORY; + if(strlen(newpasswd) < sizeof(passwd)) + strcpy(passwd, newpasswd); + + free(newpasswd); + } + } + } + } + + /************************************************************* + * Figure out the remote port number + * + * No matter if we use a proxy or not, we have to figure out the remote + * port number of various reasons. + * + * To be able to detect port number flawlessly, we must not confuse them + * IPv6-specified addresses in the [0::1] style. (RFC2732) + * + * The conn->host.name is currently [user:passwd@]host[:port] where host + * could be a hostname, IPv4 address or IPv6 address. + *************************************************************/ + if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) && + (']' == endbracket)) { + /* this is a RFC2732-style specified IP-address */ + conn->bits.ipv6_ip = TRUE; + + conn->host.name++; /* pass the starting bracket */ + tmp = strchr(conn->host.name, ']'); + *tmp = 0; /* zero terminate */ + tmp++; /* pass the ending bracket */ + if(':' != *tmp) + tmp = NULL; /* no port number available */ + } + else + tmp = strrchr(conn->host.name, ':'); + + if(data->set.use_port && data->state.allow_port) { + /* if set, we use this and ignore the port possibly given in the URL */ + conn->remote_port = (unsigned short)data->set.use_port; + if(tmp) + *tmp = '\0'; /* cut off the name there anyway - if there was a port + number - since the port number is to be ignored! */ + if(conn->bits.httpproxy) { + /* we need to create new URL with the new port number */ + char *url; + + url = aprintf("http://%s:%d%s", conn->host.name, conn->remote_port, + data->reqdata.path); + if(!url) + return CURLE_OUT_OF_MEMORY; + + if(data->change.url_alloc) + free(data->change.url); + + data->change.url = url; + data->change.url_alloc = TRUE; + } + } + else if (tmp) { + /* no CURLOPT_PORT given, extract the one from the URL */ + + char *rest; + unsigned long port; + + port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */ + + if (rest != (tmp+1) && *rest == '\0') { + /* The colon really did have only digits after it, + * so it is either a port number or a mistake */ + + if (port > 0xffff) { /* Single unix standard says port numbers are + * 16 bits long */ + failf(data, "Port number too large: %lu", port); + return CURLE_URL_MALFORMAT; + } + + *tmp = '\0'; /* cut off the name there */ + conn->remote_port = (unsigned short)port; + } + } + + /* Programmatically set password: + * - always applies, if available + * - takes precedence over the values we just set above + * so scribble it over the top. + * User-supplied passwords are assumed not to need unescaping. + * + * user_password is set in "inherit initial knowledge' above, + * so it doesn't have to be set in this block + */ + if (data->set.userpwd != NULL) { + /* the name is given, get user+password */ + sscanf(data->set.userpwd, + "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" + "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", + user, passwd); + } + + conn->bits.netrc = FALSE; + if (data->set.use_netrc != CURL_NETRC_IGNORED) { + if(Curl_parsenetrc(conn->host.name, + user, passwd, + data->set.netrc_file)) { + infof(data, "Couldn't find host %s in the " DOT_CHAR + "netrc file, using defaults\n", + conn->host.name); + } + else { + /* set bits.netrc TRUE to remember that we got the name from a .netrc + file, so that it is safe to use even if we followed a Location: to a + different host or similar. */ + conn->bits.netrc = TRUE; + + conn->bits.user_passwd = 1; /* enable user+password */ + } + } + + /* If our protocol needs a password and we have none, use the defaults */ + if ( (conn->protocol & PROT_FTP) && + !conn->bits.user_passwd) { + + conn->user = strdup(CURL_DEFAULT_USER); + conn->passwd = strdup(CURL_DEFAULT_PASSWORD); + /* This is the default password, so DON'T set conn->bits.user_passwd */ + } + else { + /* store user + password, zero-length if not set */ + conn->user = strdup(user); + conn->passwd = strdup(passwd); + } + if(!conn->user || !conn->passwd) + return CURLE_OUT_OF_MEMORY; + + /************************************************************* + * Check the current list of connections to see if we can + * re-use an already existing one or if we have to create a + * new one. + *************************************************************/ + + /* get a cloned copy of the SSL config situation stored in the + connection struct */ + if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) + return CURLE_OUT_OF_MEMORY; + + /* reuse_fresh is TRUE if we are told to use a new connection by force, but + we only acknowledge this option if this is not a re-used connection + already (which happens due to follow-location or during a HTTP + authentication phase). */ + if(data->set.reuse_fresh && !data->state.this_is_a_follow) + reuse = FALSE; + else + reuse = ConnectionExists(data, conn, &conn_temp); + + if(reuse) { + /* + * We already have a connection for this, we got the former connection + * in the conn_temp variable and thus we need to cleanup the one we + * just allocated before we can move along and use the previously + * existing one. + */ + struct connectdata *old_conn = conn; + + if(old_conn->proxy.rawalloc) + free(old_conn->proxy.rawalloc); + + /* free the SSL config struct from this connection struct as this was + allocated in vain and is targeted for destruction */ + Curl_free_ssl_config(&conn->ssl_config); + + conn = conn_temp; /* use this connection from now on */ + + conn->data = old_conn->data; + + /* get the user+password information from the old_conn struct since it may + * be new for this request even when we re-use an existing connection */ + conn->bits.user_passwd = old_conn->bits.user_passwd; + if (conn->bits.user_passwd) { + /* use the new user namd and password though */ + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); + conn->user = old_conn->user; + conn->passwd = old_conn->passwd; + old_conn->user = NULL; + old_conn->passwd = NULL; + } + + conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; + if (conn->bits.proxy_user_passwd) { + /* use the new proxy user name and proxy password though */ + Curl_safefree(conn->proxyuser); + Curl_safefree(conn->proxypasswd); + conn->proxyuser = old_conn->proxyuser; + conn->proxypasswd = old_conn->proxypasswd; + old_conn->proxyuser = NULL; + old_conn->proxypasswd = NULL; + } + + /* host can change, when doing keepalive with a proxy ! */ + if (conn->bits.httpproxy) { + free(conn->host.rawalloc); + conn->host=old_conn->host; + } + + /* get the newly set value, not the old one */ + conn->bits.no_body = old_conn->bits.no_body; + + if (!conn->bits.httpproxy) + free(old_conn->host.rawalloc); /* free the newly allocated name buffer */ + + /* re-use init */ + conn->bits.reuse = TRUE; /* yes, we're re-using here */ + conn->bits.chunk = FALSE; /* always assume not chunked unless told + otherwise */ + + Curl_safefree(old_conn->user); + Curl_safefree(old_conn->passwd); + Curl_safefree(old_conn->proxyuser); + Curl_safefree(old_conn->proxypasswd); + Curl_llist_destroy(old_conn->send_pipe, NULL); + Curl_llist_destroy(old_conn->recv_pipe, NULL); + + free(old_conn); /* we don't need this anymore */ + + /* + * If we're doing a resumed transfer, we need to setup our stuff + * properly. + */ + data->reqdata.resume_from = data->set.set_resume_from; + if (data->reqdata.resume_from) { + if (data->reqdata.rangestringalloc == TRUE) + free(data->reqdata.range); + data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", + data->reqdata.resume_from); + if(!data->reqdata.range) + return CURLE_OUT_OF_MEMORY; + + /* tell ourselves to fetch this range */ + data->reqdata.use_range = TRUE; /* enable range download */ + data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */ + } + else if (data->set.set_range) { + /* There is a range, but is not a resume, useful for random ftp access */ + data->reqdata.range = strdup(data->set.set_range); + if(!data->reqdata.range) + return CURLE_OUT_OF_MEMORY; + data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */ + data->reqdata.use_range = TRUE; /* enable range download */ + } + else + data->reqdata.use_range = FALSE; /* disable range download */ + + *in_connect = conn; /* return this instead! */ + + infof(data, "Re-using existing connection! (#%ld) with host %s\n", + conn->connectindex, + conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + } + else { + /* + * This is a brand new connection, so let's store it in the connection + * cache of ours! + */ + ConnectionStore(data, conn); + } + + /* Continue connectdata initialization here. */ + + /* + * + * Inherit the proper values from the urldata struct AFTER we have arranged + * the persistent connection stuff */ + conn->fread = data->set.fread; + conn->fread_in = data->set.in; + + if ((conn->protocol&PROT_HTTP) && + data->set.upload && + (data->set.infilesize == -1) && + (data->set.httpversion != CURL_HTTP_VERSION_1_0)) { + /* HTTP, upload, unknown file size and not HTTP 1.0 */ + conn->bits.upload_chunky = TRUE; + } + else { + /* else, no chunky upload */ + conn->bits.upload_chunky = FALSE; + } + +#ifndef USE_ARES + /************************************************************* + * Set timeout if that is being used, and we're not using an asynchronous + * name resolve. + *************************************************************/ + if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { + /************************************************************* + * Set signal handler to catch SIGALRM + * Store the old value to be able to set it back later! + *************************************************************/ + +#ifdef SIGALRM +#ifdef HAVE_ALARM + long shortest; +#endif +#ifdef HAVE_SIGACTION + struct sigaction sigact; + sigaction(SIGALRM, NULL, &sigact); + keep_sigact = sigact; + keep_copysig = TRUE; /* yes, we have a copy */ + sigact.sa_handler = alarmfunc; +#ifdef SA_RESTART + /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ + sigact.sa_flags &= ~SA_RESTART; +#endif + /* now set the new struct */ + sigaction(SIGALRM, &sigact, NULL); +#else /* HAVE_SIGACTION */ + /* no sigaction(), revert to the much lamer signal() */ +#ifdef HAVE_SIGNAL + keep_sigact = signal(SIGALRM, alarmfunc); +#endif +#endif /* HAVE_SIGACTION */ + + /* We set the timeout on the name resolving phase first, separately from + * the download/upload part to allow a maximum time on everything. This is + * a signal-based timeout, why it won't work and shouldn't be used in + * multi-threaded environments. */ + +#ifdef HAVE_ALARM + shortest = data->set.timeout; /* default to this timeout value */ + if(shortest && data->set.connecttimeout && + (data->set.connecttimeout < shortest)) + /* if both are set, pick the shortest */ + shortest = data->set.connecttimeout; + else if(!shortest) + /* if timeout is not set, use the connect timeout */ + shortest = data->set.connecttimeout; + + /* alarm() makes a signal get sent when the timeout fires off, and that + will abort system calls */ + prev_alarm = alarm((unsigned int) shortest); + /* We can expect the conn->created time to be "now", as that was just + recently set in the beginning of this function and nothing slow + has been done since then until now. */ +#endif +#endif /* SIGALRM */ + } +#endif /* USE_ARES */ + + /************************************************************* + * Resolve the name of the server or proxy + *************************************************************/ + if(conn->bits.reuse) { + /* re-used connection, no resolving is necessary */ + hostaddr = NULL; + /* we'll need to clear conn->dns_entry later in Curl_disconnect() */ + + if (conn->bits.httpproxy) + fix_hostname(data, conn, &conn->host); + } + else { + /* this is a fresh connect */ + + /* set a pointer to the hostname we display */ + fix_hostname(data, conn, &conn->host); + + if(!conn->proxy.name || !*conn->proxy.name) { + /* 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->remote_port; /* it is the same port */ + + /* Resolve target host right on */ + rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr); + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + + else if(!hostaddr) { + failf(data, "Couldn't resolve host '%s'", conn->host.dispname); + result = CURLE_COULDNT_RESOLVE_HOST; + /* don't return yet, we need to clean up the timeout first */ + } + } + else { + /* This is a proxy that hasn't been resolved yet. */ + + /* IDN-fix the proxy name */ + fix_hostname(data, conn, &conn->proxy); + + /* resolve proxy */ + rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr); + + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + + else if(!hostaddr) { + failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname); + result = CURLE_COULDNT_RESOLVE_PROXY; + /* don't return yet, we need to clean up the timeout first */ + } + } + } + *addr = hostaddr; + +#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES) + if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { +#ifdef HAVE_SIGACTION + if(keep_copysig) { + /* we got a struct as it looked before, now put that one back nice + and clean */ + sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */ + } +#else +#ifdef HAVE_SIGNAL + /* restore the previous SIGALRM handler */ + signal(SIGALRM, keep_sigact); +#endif +#endif /* HAVE_SIGACTION */ + + /* switch back the alarm() to either zero or to what it was before minus + the time we spent until now! */ + if(prev_alarm) { + /* there was an alarm() set before us, now put it back */ + unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created); + unsigned long alarm_set; + + /* the alarm period is counted in even number of seconds */ + alarm_set = prev_alarm - elapsed_ms/1000; + + if(!alarm_set || + ((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 + won't, and zero would be to switch it off so we never set it to + less than 1! */ + alarm(1); + result = CURLE_OPERATION_TIMEOUTED; + failf(data, "Previous alarm fired off!"); + } + else + alarm((unsigned int)alarm_set); + } + else + alarm(0); /* just shut it off */ + } +#endif + + return result; +} + +/* SetupConnection() is called after the name resolve initiated in + * CreateConnection() is all done. + * + * NOTE: the argument 'hostaddr' is NULL when this function is called for a + * re-used connection. + * + * conn->data MUST already have been setup fine (in CreateConnection) + */ + +static CURLcode SetupConnection(struct connectdata *conn, + struct Curl_dns_entry *hostaddr, + bool *protocol_done) +{ + CURLcode result=CURLE_OK; + struct SessionHandle *data = conn->data; + + Curl_pgrsTime(data, TIMER_NAMELOOKUP); + + if(conn->protocol & PROT_FILE) { + /* There's nothing in this function to setup if we're only doing + a file:// transfer */ + *protocol_done = TRUE; + return result; + } + *protocol_done = FALSE; /* default to not done */ + + /************************************************************* + * Send user-agent to HTTP proxies even if the target protocol + * isn't HTTP. + *************************************************************/ + if((conn->protocol&PROT_HTTP) || conn->bits.httpproxy) { + if(data->set.useragent) { + Curl_safefree(conn->allocptr.uagent); + conn->allocptr.uagent = + aprintf("User-Agent: %s\r\n", data->set.useragent); + if(!conn->allocptr.uagent) + return CURLE_OUT_OF_MEMORY; + } + } + + conn->headerbytecount = 0; + +#ifdef CURL_DO_LINEEND_CONV + data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ +#endif /* CURL_DO_LINEEND_CONV */ + + for(;;) { + /* loop for CURL_SERVER_CLOSED_CONNECTION */ + + if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { + bool connected = FALSE; + + /* Connect only if not already connected! */ + result = ConnectPlease(data, conn, hostaddr, &connected); + + if(connected) { + result = Curl_protocol_connect(conn, protocol_done); + if(CURLE_OK == result) + conn->bits.tcpconnect = TRUE; + } + else + conn->bits.tcpconnect = FALSE; + + /* if the connection was closed by the server while exchanging + authentication information, retry with the new set + authentication information */ + if(conn->bits.proxy_connect_closed) { + /* reset the error buffer */ + if (data->set.errorbuffer) + data->set.errorbuffer[0] = '\0'; + data->state.errorbuf = FALSE; + continue; + } + + if(CURLE_OK != result) + return result; + } + else { + Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ + conn->bits.tcpconnect = TRUE; + *protocol_done = TRUE; + if(data->set.verbose) + verboseconnect(conn); + } + /* Stop the loop now */ + break; + } + + conn->now = Curl_tvnow(); /* time this *after* the connect is done, we + set this here perhaps a second time */ + +#ifdef __EMX__ + /* 20000330 mgs + * the check is quite a hack... + * we're calling _fsetmode to fix the problem with fwrite converting newline + * characters (you get mangled text files, and corrupted binary files when + * you download to stdout and redirect it to a file). */ + + if ((data->set.out)->_handle == NULL) { + _fsetmode(stdout, "b"); + } +#endif + + return CURLE_OK; +} + +CURLcode Curl_connect(struct SessionHandle *data, + struct connectdata **in_connect, + bool *asyncp, + bool *protocol_done) +{ + CURLcode code; + struct Curl_dns_entry *dns; + + *asyncp = FALSE; /* assume synchronous resolves by default */ + + /* call the stuff that needs to be called */ + code = CreateConnection(data, in_connect, &dns, asyncp); + + if(CURLE_OK == code) { + /* no error */ + if(dns || !*asyncp) + /* If an address is available it means that we already have the name + resolved, OR it isn't async. if this is a re-used connection 'dns' + will be NULL here. Continue connecting from here */ + code = SetupConnection(*in_connect, dns, protocol_done); + /* else + response will be received and treated async wise */ + } + + if(CURLE_OK != code) { + /* We're not allowed to return failure with memory left allocated + in the connectdata struct, free those here */ + if(*in_connect) { + Curl_disconnect(*in_connect); /* close the connection */ + *in_connect = NULL; /* return a NULL */ + } + } + else { + if ((*in_connect)->is_in_pipeline) + data->state.is_in_pipeline = TRUE; + } + + return code; +} + +/* Call this function after Curl_connect() has returned async=TRUE and + then a successful name resolve has been received. + + Note: this function disconnects and frees the conn data in case of + resolve failure */ +CURLcode Curl_async_resolved(struct connectdata *conn, + bool *protocol_done) +{ +#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ + defined(USE_THREADING_GETADDRINFO) + CURLcode code = SetupConnection(conn, conn->async.dns, protocol_done); + + if(code) + /* We're not allowed to return failure with memory left allocated + in the connectdata struct, free those here */ + Curl_disconnect(conn); /* close the connection */ + + return code; +#else + (void)conn; + (void)protocol_done; + return CURLE_OK; +#endif +} + + +CURLcode Curl_done(struct connectdata **connp, + CURLcode status, bool premature) /* an error if this is called after an + error was detected */ +{ + CURLcode result; + struct connectdata *conn = *connp; + struct SessionHandle *data = conn->data; + + Curl_expire(data, 0); /* stop timer */ + + if(conn->bits.done) + return CURLE_OK; /* Curl_done() has already been called */ + + conn->bits.done = TRUE; /* called just now! */ + + if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && + conn->readchannel_inuse) + conn->readchannel_inuse = FALSE; + if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && + conn->writechannel_inuse) + conn->writechannel_inuse = FALSE; + + /* cleanups done even if the connection is re-used */ + if(data->reqdata.rangestringalloc) { + free(data->reqdata.range); + data->reqdata.rangestringalloc = FALSE; + } + + /* Cleanup possible redirect junk */ + if(data->reqdata.newurl) { + free(data->reqdata.newurl); + data->reqdata.newurl = NULL; + } + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ + conn->dns_entry = NULL; + } + + /* this calls the protocol-specific function pointer previously set */ + if(conn->curl_done) + result = conn->curl_done(conn, status, premature); + else + result = CURLE_OK; + + Curl_pgrsDone(conn); /* done with the operation */ + + /* for ares-using, make sure all possible outstanding requests are properly + cancelled before we proceed */ + ares_cancel(data->state.areschannel); + + /* if data->set.reuse_forbid is TRUE, it means the libcurl client has + forced us to close this no matter what we think. + + 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(data->set.reuse_forbid || conn->bits.close) { + CURLcode res2 = Curl_disconnect(conn); /* close the connection */ + + *connp = NULL; /* to make the caller of this function better detect that + this was actually killed here */ + + /* If we had an error already, make sure we return that one. But + if we got a new error, return that. */ + if(!result && res2) + result = res2; + } + else { + ConnectionDone(conn); /* the connection is no longer in use */ + + /* remember the most recently used connection */ + data->state.lastconnect = conn->connectindex; + + infof(data, "Connection #%ld to host %s left intact\n", + conn->connectindex, + conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + } + + return result; +} + +CURLcode Curl_do(struct connectdata **connp, bool *done) +{ + CURLcode result=CURLE_OK; + struct connectdata *conn = *connp; + struct SessionHandle *data = conn->data; + + conn->bits.done = FALSE; /* Curl_done() is not called yet */ + conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ + + if(conn->curl_do) { + /* generic protocol-specific function pointer set in curl_connect() */ + result = conn->curl_do(conn, done); + + /* This was formerly done in transfer.c, but we better do it here */ + + if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { + /* This was a re-use of a connection and we got a write error in the + * DO-phase. Then we DISCONNECT this connection and have another attempt + * to CONNECT and then DO again! The retry cannot possibly find another + * connection to re-use, since we only keep one possible connection for + * each. */ + + infof(data, "Re-used connection seems dead, get a new one\n"); + + conn->bits.close = TRUE; /* enforce close of this connection */ + result = Curl_done(&conn, result, FALSE); /* we are so done with this */ + + /* conn may no longer be a good pointer */ + + /* + * According to bug report #1330310. We need to check for + * CURLE_SEND_ERROR here as well. I figure this could happen when the + * request failed on a FTP connection and thus Curl_done() itself tried + * to use the connection (again). Slight Lack of feedback in the report, + * but I don't think this extra check can do much harm. + */ + if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) { + bool async; + bool protocol_done = TRUE; + + /* Now, redo the connect and get a new connection */ + result = Curl_connect(data, connp, &async, &protocol_done); + if(CURLE_OK == result) { + /* We have connected or sent away a name resolve query fine */ + + conn = *connp; /* setup conn to again point to something nice */ + if(async) { + /* Now, if async is TRUE here, we need to wait for the name + to resolve */ + result = Curl_wait_for_resolv(conn, NULL); + if(result) + return result; + + /* Resolved, continue with the connection */ + result = Curl_async_resolved(conn, &protocol_done); + if(result) + return result; + } + + /* ... finally back to actually retry the DO phase */ + result = conn->curl_do(conn, done); + } + } + } + } + return result; +} + +CURLcode Curl_do_more(struct connectdata *conn) +{ + CURLcode result=CURLE_OK; + + if(conn->curl_do_more) + result = conn->curl_do_more(conn); + + return result; +} diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h new file mode 100644 index 0000000..446b3d9 --- /dev/null +++ b/Utilities/cmcurl/lib/url.h @@ -0,0 +1,85 @@ +#ifndef __URL_H +#define __URL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include /* to make sure we have ap_list */ + +/* + * Prototypes for library-wide functions provided by url.c + */ + +CURLcode Curl_open(struct SessionHandle **curl); +CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + va_list arg); +CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ +CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, + bool *async, bool *protocol_connect); +CURLcode Curl_async_resolved(struct connectdata *conn, + bool *protocol_connect); +CURLcode Curl_do(struct connectdata **, bool *done); +CURLcode Curl_do_more(struct connectdata *); +CURLcode Curl_done(struct connectdata **, CURLcode, bool premature); +CURLcode Curl_disconnect(struct connectdata *); +CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); +CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); +CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); +void Curl_safefree(void *ptr); + +/* create a connection cache */ +struct conncache *Curl_mk_connc(int type, int amount); +/* free a connection cache */ +void Curl_rm_connc(struct conncache *c); +/* Change number of entries of a connection cache */ +CURLcode Curl_ch_connc(struct SessionHandle *data, + struct conncache *c, + long newamount); + +int Curl_protocol_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); +int Curl_doing_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + +void Curl_addHandleToPipeline(struct SessionHandle *handle, + struct curl_llist *pipe); +int Curl_removeHandleFromPipeline(struct SessionHandle *handle, + struct curl_llist *pipe); +bool Curl_isHandleAtHead(struct SessionHandle *handle, + struct curl_llist *pipe); + +void Curl_close_connections(struct SessionHandle *data); + +#if 0 +CURLcode Curl_protocol_fdset(struct connectdata *conn, + fd_set *read_fd_set, + fd_set *write_fd_set, + int *max_fdp); +CURLcode Curl_doing_fdset(struct connectdata *conn, + fd_set *read_fd_set, + fd_set *write_fd_set, + int *max_fdp); +#endif + +#endif diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h new file mode 100644 index 0000000..46d956d --- /dev/null +++ b/Utilities/cmcurl/lib/urldata.h @@ -0,0 +1,1340 @@ +#ifndef __URLDATA_H +#define __URLDATA_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +/* This file is for lib internal stuff */ + +#include "setup.h" + +#define PORT_FTP 21 +#define PORT_FTPS 990 +#define PORT_TELNET 23 +#define PORT_HTTP 80 +#define PORT_HTTPS 443 +#define PORT_DICT 2628 +#define PORT_LDAP 389 +#define PORT_TFTP 69 +#define PORT_SSH 22 + +#define DICT_MATCH "/MATCH:" +#define DICT_MATCH2 "/M:" +#define DICT_MATCH3 "/FIND:" +#define DICT_DEFINE "/DEFINE:" +#define DICT_DEFINE2 "/D:" +#define DICT_DEFINE3 "/LOOKUP:" + +#define CURL_DEFAULT_USER "anonymous" +#define CURL_DEFAULT_PASSWORD "curl_by_daniel@haxx.se" + +#include "cookie.h" +#include "formdata.h" + +#ifdef USE_SSLEAY +#ifdef USE_OPENSSL +#include "openssl/rsa.h" +#include "openssl/crypto.h" +#include "openssl/x509.h" +#include "openssl/pem.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif +#ifdef HAVE_OPENSSL_PKCS12_H +#include +#endif +#else /* SSLeay-style includes */ +#include "rsa.h" +#include "crypto.h" +#include "x509.h" +#include "pem.h" +#include "ssl.h" +#include "err.h" +#endif /* USE_OPENSSL */ +#endif /* USE_SSLEAY */ + +#ifdef USE_GNUTLS +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "timeval.h" + +#ifdef HAVE_ZLIB_H +#include /* for content-encoding */ +#endif + +#ifdef USE_ARES +#include +#endif + +#include + +#include "http_chunks.h" /* for the structs and enum stuff */ +#include "hostip.h" +#include "hash.h" +#include "splay.h" + +#ifdef HAVE_GSSAPI +# ifdef HAVE_GSSGNU +# include +# elif defined HAVE_GSSMIT +# include +# include +# else +# include +# endif +#endif + +#ifdef HAVE_LIBSSH2_H +#include +#include +#endif /* HAVE_LIBSSH2_H */ + +/* Download buffer size, keep it fairly big for speed reasons */ +#undef BUFSIZE +#define BUFSIZE CURL_MAX_WRITE_SIZE + +/* Initial size of the buffer to store headers in, it'll be enlarged in case + of need. */ +#define HEADERSIZE 256 + +#define CURLEASY_MAGIC_NUMBER 0xc0dedbad + +/* Just a convenience macro to get the larger value out of two given. + We prefix with CURL to prevent name collisions. */ +#define CURLMAX(x,y) ((x)>(y)?(x):(y)) + +#ifdef HAVE_KRB4 +/* Types needed for krb4-ftp connections */ +struct krb4buffer { + void *data; + size_t size; + size_t index; + int eof_flag; +}; +enum protection_level { + prot_clear, + prot_safe, + prot_confidential, + prot_private +}; +#endif + +/* 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; + +/* struct for data related to each SSL connection */ +struct ssl_connect_data { + bool use; /* use ssl encrypted communications TRUE/FALSE */ +#ifdef USE_SSLEAY + /* these ones requires specific SSL-types */ + SSL_CTX* ctx; + SSL* handle; + X509* server_cert; + ssl_connect_state connecting_state; +#endif /* USE_SSLEAY */ +#ifdef USE_GNUTLS + gnutls_session session; + gnutls_certificate_credentials cred; +#endif /* USE_GNUTLS */ +}; + +struct ssl_config_data { + long version; /* what version the client wants to use */ + long certverifyresult; /* result from the certificate verification */ + long verifypeer; /* set TRUE if this is desired */ + long verifyhost; /* 0: no verify + 1: check that CN exists + 2: CN must match hostname */ + char *CApath; /* DOES NOT WORK ON WINDOWS */ + char *CAfile; /* cerficate to verify peer against */ + char *random_file; /* path to file containing "random" data */ + char *egdsocket; /* path to file containing the EGD daemon socket */ + char *cipher_list; /* list of ciphers to use */ + long numsessions; /* SSL session id cache size */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + bool sessionid; /* cache session IDs or not */ +}; + +/* information stored about one single SSL session */ +struct curl_ssl_session { + char *name; /* host name for which this ID was used */ + void *sessionid; /* as returned from the SSL layer */ + size_t idsize; /* if known, otherwise 0 */ + long age; /* just a number, the higher the more recent */ + unsigned short remote_port; /* remote port to connect to */ + struct ssl_config_data ssl_config; /* setup for this session */ +}; + +/* Struct used for Digest challenge-response authentication */ +struct digestdata { + char *nonce; + char *cnonce; + char *realm; + int algo; + bool stale; /* set true for re-negotiation */ + char *opaque; + char *qop; + char *algorithm; + int nc; /* nounce count */ +}; + +typedef enum { + NTLMSTATE_NONE, + NTLMSTATE_TYPE1, + NTLMSTATE_TYPE2, + NTLMSTATE_TYPE3, + NTLMSTATE_LAST +} curlntlm; + +#ifdef USE_WINDOWS_SSPI +/* When including these headers, you must define either SECURITY_WIN32 + * or SECURITY_KERNEL, indicating who is compiling the code. + */ +#define SECURITY_WIN32 1 +#include +#include +#include +#endif + +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) +#include +#endif + +/* Struct used for NTLM challenge-response authentication */ +struct ntlmdata { + curlntlm state; +#ifdef USE_WINDOWS_SSPI + CredHandle handle; + CtxtHandle c_handle; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + int has_handles; + void *type_2; + int n_type_2; +#else + unsigned int flags; + unsigned char nonce[8]; +#endif +}; + +#ifdef HAVE_GSSAPI +struct negotiatedata { + bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */ + const char* protocol; /* "GSS-Negotiate" or "Negotiate" */ + OM_uint32 status; + gss_ctx_id_t context; + gss_name_t server_name; + gss_buffer_desc output_token; +}; +#endif + +/**************************************************************************** + * HTTP unique setup + ***************************************************************************/ +struct HTTP { + struct FormData *sendit; + curl_off_t postsize; /* off_t to handle large file sizes */ + char *postdata; + + const char *p_pragma; /* Pragma: string */ + const char *p_accept; /* Accept: string */ + curl_off_t readbytecount; + curl_off_t writebytecount; + + /* For FORM posting */ + struct Form form; + struct Curl_chunker chunk; + + struct back { + curl_read_callback fread; /* backup storage for fread pointer */ + void *fread_in; /* backup storage for fread_in pointer */ + char *postdata; + curl_off_t postsize; + } backup; + + enum { + HTTPSEND_NADA, /* init */ + HTTPSEND_REQUEST, /* sending a request */ + HTTPSEND_BODY, /* sending body */ + HTTPSEND_LAST /* never use this */ + } sending; + + void *send_buffer; /* used if the request couldn't be sent in one chunk, + points to an allocated send_buffer struct */ +}; + +/**************************************************************************** + * FTP unique setup + ***************************************************************************/ +typedef enum { + FTP_STOP, /* do nothing state, stops the state machine */ + FTP_WAIT220, /* waiting for the initial 220 response immediately after + a connect */ + FTP_AUTH, + FTP_USER, + FTP_PASS, + FTP_ACCT, + FTP_PBSZ, + FTP_PROT, + FTP_CCC, + FTP_PWD, + FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ + FTP_RETR_PREQUOTE, + FTP_STOR_PREQUOTE, + FTP_POSTQUOTE, + FTP_CWD, /* change dir */ + 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 */ + FTP_RETR_TYPE, /* set type when about to RETR a file */ + FTP_STOR_TYPE, /* set type when about to STOR a file */ + FTP_SIZE, /* get the remote file's size for head-like request */ + FTP_RETR_SIZE, /* get the remote file's size for RETR */ + FTP_STOR_SIZE, /* get the size for (resumed) STOR */ + FTP_REST, /* when used to check if the server supports it in head-like */ + FTP_RETR_REST, /* when asking for "resume" in for RETR */ + FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */ + FTP_PASV, /* generic state for PASV and EPSV, check count1 */ + FTP_LIST, /* generic state for LIST, NLST or a custom list command */ + FTP_RETR, + FTP_STOR, /* generic state for STOR and APPE */ + FTP_QUIT, + FTP_LAST /* never used */ +} ftpstate; + +typedef enum { + FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */ + FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */ + FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */ +} curl_ftpfile; + +/* This FTP struct is used in the SessionHandle. All FTP data that is + connection-oriented must be in FTP_conn to properly deal with the fact that + perhaps the SessionHandle is changed between the times the connection is + used. */ +struct FTP { + curl_off_t *bytecountp; + char *user; /* user name string */ + char *passwd; /* password string */ + char *urlpath; /* the originally given path part of the URL */ + char *file; /* decoded file */ + bool no_transfer; /* nothing was transfered, (possibly because a resumed + transfer already was complete) */ + curl_off_t downloadsize; +}; + +/* ftp_conn is used for striuct connection-oriented data in the connectdata + struct */ +struct ftp_conn { + char *entrypath; /* the PWD reply when we logged on */ + char **dirs; /* realloc()ed array for path components */ + int dirdepth; /* number of entries used in the 'dirs' array */ + int diralloc; /* number of entries allocated for the 'dirs' array */ + char *cache; /* data cache between getresponse()-calls */ + curl_off_t cache_size; /* size of cache in bytes */ + bool dont_check; /* Set to TRUE to prevent the final (post-transfer) + file size and 226/250 status check. It should still + read the line, just ignore the result. */ + long response_time; /* When no timeout is given, this is the amount of + seconds we await for an FTP response. Initialized + in Curl_ftp_connect() */ + bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If + the connection has timed out or been closed, this + should be FALSE when it gets to Curl_ftp_quit() */ + bool cwddone; /* if it has been determined that the proper CWD combo + already has been done */ + bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent + caching the current directory */ + char *prevpath; /* conn->path from the previous transfer */ + char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a + and others (A/I or zero) */ + size_t nread_resp; /* number of bytes currently read of a server response */ + char *linestart_resp; /* line start pointer for the FTP server response + reader function */ + + 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 */ + char *sendthis; /* allocated pointer to a buffer that is to be sent to the + ftp server */ + size_t sendleft; /* number of bytes left to send from the sendthis buffer */ + size_t sendsize; /* total size of the sendthis buffer */ + struct timeval response; /* set to Curl_tvnow() when a command has been sent + off, used to time-out response reading */ + ftpstate state; /* always use ftp.c:state() to change state! */ +}; + +struct SSHPROTO { + curl_off_t *bytecountp; + char *user; + char *passwd; + char *path; /* the path we operate on */ + char *homedir; + char *errorstr; +#ifdef USE_LIBSSH2 + LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ + LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ + LIBSSH2_SFTP *sftp_session; /* SFTP handle */ + LIBSSH2_SFTP_HANDLE *sftp_handle; +#endif /* USE_LIBSSH2 */ +}; + + +/**************************************************************************** + * FILE unique setup + ***************************************************************************/ +struct FILEPROTO { + char *path; /* the path we operate on */ + char *freepath; /* pointer to the allocated block we must free, this might + differ from the 'path' pointer */ + int fd; /* open file descriptor to read from! */ +}; + +/* + * Boolean values that concerns this connection. + */ +struct ConnectBits { + bool close; /* if set, we close the connection after this request */ + bool reuse; /* if set, this is a re-used connection */ + bool chunk; /* if set, this is a chunked transfer-encoding */ + bool httpproxy; /* if set, this transfer is done through a http proxy */ + bool user_passwd; /* do we use user+password for this connection? */ + bool proxy_user_passwd; /* user+password for the proxy? */ + bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6 + IP address */ + bool ipv6; /* we communicate with a site using an IPv6 address */ + + bool do_more; /* this is set TRUE if the ->curl_do_more() function is + supposed to be called, after ->curl_do() */ + + bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding + on upload */ + bool getheader; /* TRUE if header parsing is wanted */ + + bool forbidchunk; /* used only to explicitly forbid chunk-upload for + specific upload buffers. See readmoredata() in + http.c for details. */ + + bool tcpconnect; /* the TCP layer (or simimlar) is connected, this is set + the first time on the first connect function call */ + bool protoconnstart;/* the protocol layer has STARTED its operation after + the TCP layer connect */ + + bool retry; /* this connection is about to get closed and then + re-attempted at another connection. */ + bool no_body; /* CURLOPT_NO_BODY (or similar) was set */ + bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy. + This is implicit when SSL-protocols are used through + proxies, but can also be enabled explicitly by + apps */ + bool 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. */ + bool rewindaftersend;/* TRUE when the sending couldn't be stopped even + though it will be discarded. When the whole send + operation is done, we must call the data rewind + callback. */ + bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out + EPSV doesn't work we disable it for the forthcoming + requests */ + + bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out + EPRT doesn't work we disable it for the forthcoming + requests */ + bool netrc; /* name+password provided by netrc */ + + bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response. + Required to determine whether to look for trailers + in case of Transfer-Encoding: chunking */ + bool done; /* set to FALSE when Curl_do() is called and set to TRUE + when Curl_done() is called, to prevent Curl_done() to + get invoked twice when the multi interface is + used. */ + bool stream_was_rewound; /* Indicates that the stream was rewound after a + request read past the end of its response byte + boundary */ + bool proxy_connect_closed; /* set true if a proxy disconnected the + connection in a CONNECT request with auth, so + that libcurl should reconnect and continue. */ +}; + +struct hostname { + char *rawalloc; /* allocated "raw" version of the name */ + char *encalloc; /* allocated IDN-encoded version of the name */ + char *name; /* name to use internally, might be encoded, might be raw */ + char *dispname; /* name to display, as 'name' might be encoded */ +}; + +/* + * Flags on the keepon member of the Curl_transfer_keeper + */ + +#define KEEP_NONE 0 +#define KEEP_READ 1 /* there is or may be data to read */ +#define KEEP_WRITE 2 /* there is or may be data to write */ +#define KEEP_READ_HOLD 4 /* when set, no reading should be done but there + might still be data to read */ +#define KEEP_WRITE_HOLD 8 /* when set, no writing should be done but there + might still be data to write */ + +/* + * This struct is all the previously local variables from Curl_perform() moved + * to struct to allow the function to return and get re-invoked better without + * losing state. + */ + +struct Curl_transfer_keeper { + + /** Values copied over from the HandleData struct each time on init **/ + + curl_off_t size; /* -1 if unknown at this point */ + curl_off_t *bytecountp; /* return number of bytes read or NULL */ + + curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0 + means unlimited */ + curl_off_t *writebytecountp; /* return number of bytes written or NULL */ + + /** End of HandleData struct copies **/ + + curl_off_t bytecount; /* total number of bytes read */ + curl_off_t writebytecount; /* number of bytes written */ + + struct timeval start; /* transfer started at this time */ + struct timeval now; /* current time */ + bool header; /* incoming data has HTTP header */ + enum { + HEADER_NORMAL, /* no bad header at all */ + HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest + is normal data */ + HEADER_ALLBAD /* all was believed to be header */ + } badheader; /* the header was deemed bad and will be + written as body */ + int headerline; /* counts header lines to better track the + first one */ + char *hbufp; /* points at *end* of header line */ + size_t hbuflen; + char *str; /* within buf */ + char *str_start; /* within buf */ + char *end_ptr; /* within buf */ + char *p; /* within headerbuff */ + bool content_range; /* set TRUE if Content-Range: was found */ + curl_off_t offset; /* possible resume offset read from the + Content-Range: header */ + int httpcode; /* error code from the 'HTTP/1.? XXX' line */ + int httpversion; /* the HTTP version*10 */ + struct timeval start100; /* time stamp to wait for the 100 code from */ + bool write_after_100_header; /* TRUE = we enable the write after we + received a 100-continue/timeout or + FALSE = directly */ + bool wait100_after_headers; /* TRUE = after the request-headers have been + sent off properly, we go into the wait100 + state, FALSE = don't */ + int content_encoding; /* What content encoding. sec 3.5, RFC2616. */ + +#define IDENTITY 0 /* No encoding */ +#define DEFLATE 1 /* zlib delfate [RFC 1950 & 1951] */ +#define GZIP 2 /* gzip algorithm [RFC 1952] */ +#define COMPRESS 3 /* Not handled, added for completeness */ + +#ifdef HAVE_LIBZ + bool zlib_init; /* True if zlib already initialized; + undefined if Content-Encoding header. */ + z_stream z; /* State structure for zlib. */ +#endif + + time_t timeofdoc; + long bodywrites; + + char *buf; + char *uploadbuf; + curl_socket_t maxfd; + + int keepon; + + bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload + and we're uploading the last chunk */ + + bool ignorebody; /* we read a response-body but we ignore it! */ + bool ignorecl; /* This HTTP response has no body so we ignore the Content- + Length: header */ +}; + +#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ + defined(USE_THREADING_GETADDRINFO) +struct Curl_async { + char *hostname; + int port; + struct Curl_dns_entry *dns; + bool done; /* set TRUE when the lookup is complete */ + int status; /* if done is TRUE, this is the status from the callback */ + void *os_specific; /* 'struct thread_data' for Windows */ +}; +#endif + +#define FIRSTSOCKET 0 +#define SECONDARYSOCKET 1 + +/* These function pointer types are here only to allow easier typecasting + within the source when we need to cast between data pointers (such as NULL) + and function pointers. */ +typedef CURLcode (*Curl_do_more_func)(struct connectdata *); +typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool); + + +/* + * Store's request specific data in the easy handle (SessionHandle). + * Previously, these members were on the connectdata struct but since + * a conn struct may now be shared between different SessionHandles, + * we store connection-specific data here. + * + */ +struct HandleData { + char *pathbuffer;/* allocated buffer to store the URL's path part in */ + char *path; /* path to use, points to somewhere within the pathbuffer + area */ + + char *newurl; /* This can only be set if a Location: was in the + document headers */ + + /* This struct is inited when needed */ + struct Curl_transfer_keeper keep; + + /* '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; + + curl_off_t size; /* -1 if unknown at this point */ + curl_off_t *bytecountp; /* return number of bytes read or NULL */ + + curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0 + means unlimited */ + curl_off_t *writebytecountp; /* return number of bytes written or NULL */ + + bool use_range; + bool rangestringalloc; /* the range string is malloc()'ed */ + + char *range; /* range, if used. See README for detailed specification on + this syntax. */ + curl_off_t resume_from; /* continue [ftp] transfer from here */ + + /* Protocol specific data */ + + union { + struct HTTP *http; + struct HTTP *https; /* alias, just for the sake of being more readable */ + struct FTP *ftp; + void *tftp; /* private for tftp.c-eyes only */ + struct FILEPROTO *file; + void *telnet; /* private for telnet.c-eyes only */ + void *generic; + struct SSHPROTO *ssh; + } proto; +}; + +/* + * The connectdata struct contains all fields and variables that should be + * unique for an entire connection. + */ +struct connectdata { + /* 'data' is the CURRENT SessionHandle using this connection -- take great + caution that this might very well vary between different times this + connection is used! */ + struct SessionHandle *data; + + bool inuse; /* This is a marker for the connection cache logic. If this is + TRUE this handle is being used by an easy handle and cannot + be used by any other easy handle without careful + consideration (== only for pipelining). */ + + /**** Fields set when inited and not modified again */ + long connectindex; /* what index in the connection cache connects index this + particular struct has */ + long protocol; /* PROT_* flags concerning the protocol set */ +#define PROT_MISSING (1<<0) +#define PROT_HTTP (1<<2) +#define PROT_HTTPS (1<<3) +#define PROT_FTP (1<<4) +#define PROT_TELNET (1<<5) +#define PROT_DICT (1<<6) +#define PROT_LDAP (1<<7) +#define PROT_FILE (1<<8) +#define PROT_FTPS (1<<9) +#define PROT_SSL (1<<10) /* protocol requires SSL */ +#define PROT_TFTP (1<<11) +#define PROT_SCP (1<<12) +#define PROT_SFTP (1<<13) + +#define PROT_CLOSEACTION PROT_FTP /* these ones need action before socket + close */ + + /* '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 + Curl_done(). This entry will be NULL if the connection is re-used as then + there is no name resolve done. */ + struct Curl_dns_entry *dns_entry; + + /* 'ip_addr' is the particular IP we connected to. It points to a struct + within the DNS cache, so this pointer is only valid as long as the DNS + cache entry remains locked. It gets unlocked in Curl_done() */ + Curl_addrinfo *ip_addr; + + /* 'ip_addr_str' is the ip_addr data as a human readable malloc()ed string. + It remains available as long as the connection does, which is longer than + the ip_addr itself. Set with Curl_store_ip_addr() when ip_addr has been + set. */ + char *ip_addr_str; + + char protostr[16]; /* store the protocol string in this buffer */ + int socktype; /* SOCK_STREAM or SOCK_DGRAM */ + + struct hostname host; + struct hostname proxy; + + long port; /* which port to use locally */ + unsigned short remote_port; /* what remote port to connect to, + not the proxy port! */ + + long headerbytecount; /* only count received headers */ + long deductheadercount; /* this amount of bytes doesn't count when we check + if anything has been transfered 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 */ + + char *user; /* user name string, allocated */ + char *passwd; /* password string, allocated */ + + char *proxyuser; /* proxy user name string, allocated */ + char *proxypasswd; /* proxy password string, allocated */ + + struct timeval now; /* "current" time */ + struct timeval created; /* creation time */ + curl_socket_t sock[2]; /* two sockets, the second is used for the data + transfer when doing FTP */ + + struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ + struct ssl_config_data ssl_config; + + struct ConnectBits bits; /* various state-flags for this connection */ + + /* These two functions MUST be set by the curl_connect() function to be + be protocol dependent */ + CURLcode (*curl_do)(struct connectdata *, bool *done); + Curl_done_func curl_done; + + /* If the curl_do() function is better made in two halves, this + * curl_do_more() function will be called afterwards, if set. For example + * for doing the FTP stuff after the PASV/PORT command. + */ + Curl_do_more_func curl_do_more; + + /* 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 doesn't complete, the caller + * should call the curl_connecting() function until it is. + */ + CURLcode (*curl_connect)(struct connectdata *, bool *done); + + /* See above. Currently only used for FTP. */ + CURLcode (*curl_connecting)(struct connectdata *, bool *done); + CURLcode (*curl_doing)(struct connectdata *, bool *done); + + /* Called from the multi interface during the PROTOCONNECT phase, and it + should then return a proper fd set */ + int (*curl_proto_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + + /* Called from the multi interface during the DOING phase, and it should + then return a proper fd set */ + int (*curl_doing_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + + /* This function *MAY* be set to a protocol-dependent function that is run + * by the curl_disconnect(), as a step in the disconnection. + */ + CURLcode (*curl_disconnect)(struct connectdata *); + + /* This function *MAY* be set to a protocol-dependent function that is run + * in the curl_close() function if protocol-specific cleanups are required. + */ + CURLcode (*curl_close)(struct connectdata *); + + /**** curl_get() phase fields */ + + curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ + curl_socket_t writesockfd; /* socket to write to, it may very + well be the same we read from. + CURL_SOCKET_BAD disables */ + + /** Dynamicly allocated strings, may need to be freed before this **/ + /** struct is killed. **/ + struct dynamically_allocated_data { + char *proxyuserpwd; /* free later if not NULL! */ + char *uagent; /* free later if not NULL! */ + char *accept_encoding; /* free later if not NULL! */ + char *userpwd; /* free later if not NULL! */ + char *rangeline; /* free later if not NULL! */ + char *ref; /* free later if not NULL! */ + char *host; /* free later if not NULL */ + char *cookiehost; /* free later if not NULL */ + } allocptr; + + int sec_complete; /* if krb4 is enabled for this connection */ +#ifdef HAVE_KRB4 + enum protection_level command_prot; + enum protection_level data_prot; + enum protection_level request_data_prot; + size_t buffer_size; + struct krb4buffer in_buffer, out_buffer; + void *app_data; + const struct Curl_sec_client_mech *mech; + struct sockaddr_in local_addr; +#endif + + bool readchannel_inuse; /* whether the read channel is in use by an easy + handle */ + bool writechannel_inuse; /* whether the write channel is in use by an easy + handle */ + bool is_in_pipeline; /* TRUE if this connection is in a pipeline */ + + struct curl_llist *send_pipe; /* List of handles waiting to + send on this pipeline */ + struct curl_llist *recv_pipe; /* List of handles waiting to read + their responses on this pipeline */ + + char master_buffer[BUFSIZE]; /* The master buffer for this connection. */ + size_t read_pos; /* Current read position in the master buffer */ + size_t buf_len; /* Length of the buffer?? */ + + + /*************** Request - specific items ************/ + + /* previously this was in the urldata struct */ + curl_read_callback fread; /* function that reads the input */ + void *fread_in; /* pointer to pass to the fread() above */ + + struct ntlmdata ntlm; /* NTLM differs from other authentication schemes + because it authenticates connections, not + single requests! */ + struct ntlmdata proxyntlm; /* NTLM data for proxy */ + + char syserr_buf [256]; /* buffer for Curl_strerror() */ + +#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ + defined(USE_THREADING_GETADDRINFO) + /* data used for the asynch name resolve callback */ + struct Curl_async async; +#endif + + /* These three are used for chunked-encoding trailer support */ + char *trailer; /* allocated buffer to store trailer in */ + int trlMax; /* allocated buffer size */ + int trlPos; /* index of where to store data */ + + union { + struct ftp_conn ftpc; + } proto; +}; + +/* The end of connectdata. */ + +/* + * Struct to keep statistical and informational data. + */ +struct PureInfo { + int httpcode; /* Recent HTTP or FTP response code */ + int httpproxycode; + int httpversion; + long filetime; /* If requested, this is might get set. Set to -1 if the time + was unretrievable. We cannot have this of type time_t, + since time_t is unsigned on several platforms such as + OpenVMS. */ + long header_size; /* size of read header(s) in bytes */ + long request_size; /* the amount of bytes sent in the request(s) */ + + long proxyauthavail; + long httpauthavail; + + long numconnects; /* how many new connection did libcurl created */ + + char *contenttype; /* the content type of the object */ +}; + + +struct Progress { + long lastshow; /* time() of the last displayed progress meter or NULL to + force redraw at next call */ + curl_off_t size_dl; /* total expected size */ + curl_off_t size_ul; /* total expected size */ + curl_off_t downloaded; /* transfered so far */ + curl_off_t uploaded; /* transfered so far */ + + curl_off_t current_speed; /* uses the currently fastest transfer */ + + bool callback; /* set when progress callback is used */ + int width; /* screen width at download start */ + int flags; /* see progress.h */ + + double timespent; + + curl_off_t dlspeed; + curl_off_t ulspeed; + + double t_nslookup; + double t_connect; + double t_pretransfer; + double t_starttransfer; + double t_redirect; + + struct timeval start; + struct timeval t_startsingle; +#define CURR_TIME (5+1) /* 6 entries for 5 seconds */ + + curl_off_t speeder[ CURR_TIME ]; + struct timeval speeder_time[ CURR_TIME ]; + int speeder_c; +}; + +typedef enum { + HTTPREQ_NONE, /* first in list */ + HTTPREQ_GET, + HTTPREQ_POST, + HTTPREQ_POST_FORM, /* we make a difference internally */ + HTTPREQ_PUT, + HTTPREQ_HEAD, + HTTPREQ_CUSTOM, + HTTPREQ_LAST /* last in list */ +} Curl_HttpReq; + +/* + * Values that are generated, temporary or calculated internally for a + * "session handle" must be defined within the 'struct UrlState'. This struct + * will be used within the SessionHandle struct. When the 'SessionHandle' + * struct is cloned, this data MUST NOT be copied. + * + * Remember that any "state" information goes globally for the curl handle. + * Session-data MUST be put in the connectdata struct and here. */ +#define MAX_CURL_USER_LENGTH 256 +#define MAX_CURL_PASSWORD_LENGTH 256 +#define MAX_CURL_USER_LENGTH_TXT "255" +#define MAX_CURL_PASSWORD_LENGTH_TXT "255" + +struct auth { + long want; /* Bitmask set to the authentication methods wanted by the app + (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ + long picked; + long avail; /* bitmask for what the server reports to support for this + resource */ + bool done; /* TRUE when the auth phase is done and ready to do the *actual* + request */ + bool multi; /* TRUE if this is not yet authenticated but within the auth + multipass negotiation */ + +}; + +struct conncache { + /* 'connects' will be an allocated array with pointers. If the pointer is + set, it holds an allocated connection. */ + struct connectdata **connects; + long num; /* number of entries of the 'connects' array */ + enum { + CONNCACHE_PRIVATE, /* used for an easy handle alone */ + CONNCACHE_MULTI /* shared within a multi handle */ + } type; +}; + + +struct UrlState { + enum { + Curl_if_none, + Curl_if_easy, + Curl_if_multi + } used_interface; + + struct conncache *connc; /* points to the connection cache this handle + uses */ + + /* buffers to store authentication data in, as parsed from input options */ + struct timeval keeps_speed; /* for the progress meter really */ + + long lastconnect; /* index of most recent connect or -1 if undefined */ + + char *headerbuff; /* allocated buffer to store headers in */ + size_t headersize; /* size of the allocation */ + + char buffer[BUFSIZE+1]; /* download buffer */ + char uploadbuffer[BUFSIZE+1]; /* upload buffer */ + curl_off_t current_speed; /* the ProgressShow() funcion sets this, + bytes / second */ + bool this_is_a_follow; /* this is a followed Location: request */ + + bool is_in_pipeline; /* Indicates whether this handle is part of a pipeline */ + + char *first_host; /* 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() data. + */ + + struct curl_ssl_session *session; /* array of 'numsessions' size */ + long sessionage; /* number of the most recent session */ + + char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */ + bool errorbuf; /* Set to TRUE if the error buffer is already filled in. + This must be set to FALSE every time _easy_perform() is + called. */ + int os_errno; /* filled in with errno whenever an error occurs */ +#ifdef HAVE_SIGNAL + /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ + void (*prev_signal)(int sig); +#endif + bool allow_port; /* Is set.use_port allowed to take effect or not. This + is always set TRUE when curl_easy_perform() is called. */ + + struct digestdata digest; + struct digestdata proxydigest; + +#ifdef HAVE_GSSAPI + struct negotiatedata negotiate; +#endif + + struct auth authhost; + struct auth authproxy; + + bool authproblem; /* TRUE if there's some problem authenticating */ + +#ifdef USE_ARES + ares_channel areschannel; /* for name resolves */ +#endif + +#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) + ENGINE *engine; +#endif /* USE_SSLEAY */ + struct timeval expiretime; /* set this with Curl_expire() only */ + struct Curl_tree timenode; /* for the splay stuff */ + + /* a place to store the most recenlty set FTP entrypath */ + char *most_recent_ftp_entrypath; + + /* set after initial USER failure, to prevent an authentication loop */ + bool ftp_trying_alternative; + + bool expect100header; /* TRUE if we added Expect: 100-continue */ + + bool pipe_broke; /* TRUE if the connection we were pipelined on broke + and we need to restart from the beginning */ + bool cancelled; /* TRUE if the request was cancelled */ + +#ifndef WIN32 +/* do FTP line-end conversions on most platforms */ +#define CURL_DO_LINEEND_CONV + /* for FTP downloads: track CRLF sequences that span blocks */ + bool prev_block_had_trailing_cr; + /* for FTP downloads: how many CRLFs did we converted to LFs? */ + curl_off_t crlf_conversions; +#endif + /* If set to non-NULL, there's a connection in a shared connection cache + that uses this handle so we can't kill this SessionHandle just yet but + must keep it around and add it to the list of handles to kill once all + its connections are gone */ + void *shared_conn; + bool closed; /* set to TRUE when curl_easy_cleanup() has been called on this + handle, but it is kept around as mentioned for + shared_conn */ +}; + + +/* + * This 'DynamicStatic' struct defines dynamic states that actually change + * values in the 'UserDefined' area, which MUST be taken into consideration + * if the UserDefined struct is cloned or similar. You can probably just + * copy these, but each one indicate a special action on other data. + */ + +struct DynamicStatic { + char *url; /* work URL, copied from UserDefined */ + bool url_alloc; /* URL string is malloc()'ed */ + bool url_changed; /* set on CURL_OPT_URL, used to detect if the URL was + changed after the connect phase, as we allow callback + to change it and if so, we reconnect to use the new + URL instead */ + char *referer; /* referer string */ + bool referer_alloc; /* referer sting is malloc()ed */ + struct curl_slist *cookielist; /* list of cookie files set by + curl_easy_setopt(COOKIEFILE) calls */ +}; + +/* + * This 'UserDefined' struct must only contain data that is set once to go + * for many (perhaps) independent connections. Values that are generated or + * calculated internally for the "session handle" MUST be defined within the + * 'struct UrlState' instead. The only exceptions MUST note the changes in + * the 'DynamicStatic' struct. + */ +struct Curl_one_easy; /* declared and used only in multi.c */ +struct Curl_multi; /* declared and used only in multi.c */ + +struct UserDefined { + FILE *err; /* the stderr user data goes here */ + void *debugdata; /* the data that will be passed to fdebug */ + char *errorbuffer; /* store failure messages in here */ + char *proxyuserpwd; /* Proxy , if used */ + long proxyport; /* If non-zero, use this port number by default. If the + proxy string features a ":[port]" that one will override + this. */ + void *out; /* the fetched file goes here */ + void *in; /* the uploaded file is read from here */ + void *writeheader; /* write the header to this if non-NULL */ + char *set_url; /* what original URL to work on */ + char *proxy; /* proxy to use */ + long use_port; /* which port to use (when not using default) */ + char *userpwd; /* , if used */ + long httpauth; /* what kind of HTTP authentication to use (bitmask) */ + long proxyauth; /* what kind of proxy authentication to use (bitmask) */ + char *set_range; /* range, if used. See README for detailed specification + on this syntax. */ + long followlocation; /* as in HTTP Location: */ + long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 + for infinity */ + char *set_referer; /* custom string */ + bool free_referer; /* set TRUE if 'referer' points to a string we + allocated */ + char *useragent; /* User-Agent string */ + char *encoding; /* Accept-Encoding string */ + char *postfields; /* if POST, set the fields' values here */ + curl_off_t postfieldsize; /* if POST, this might have a size to use instead + of strlen(), and then the data *may* be binary + (contain zero bytes) */ + char *ftpport; /* port to send with the FTP PORT command */ + char *device; /* local network interface/address to use */ + unsigned short localport; /* local port number to bind to */ + int localportrange; /* number of additional port numbers to test in case the + 'localport' one can't be bind()ed */ + curl_write_callback fwrite; /* function that stores the output */ + curl_write_callback fwrite_header; /* function that stores headers */ + curl_read_callback fread; /* function that reads the input */ + curl_progress_callback fprogress; /* function for progress information */ + curl_debug_callback fdebug; /* function that write informational data */ + curl_ioctl_callback ioctl; /* function for I/O control */ + curl_sockopt_callback fsockopt; /* function for setting socket options */ + void *sockopt_client; /* pointer to pass to the socket options callback */ + + /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ + /* function to convert from the network encoding: */ + curl_conv_callback convfromnetwork; + /* function to convert to the network encoding: */ + curl_conv_callback convtonetwork; + /* function to convert from UTF-8 encoding: */ + curl_conv_callback convfromutf8; + + void *progress_client; /* pointer to pass to the progress callback */ + void *ioctl_client; /* pointer to pass to the ioctl callback */ + long timeout; /* in seconds, 0 means no timeout */ + long connecttimeout; /* in seconds, 0 means no timeout */ + long ftp_response_timeout; /* in seconds, 0 means no timeout */ + curl_off_t infilesize; /* size of file to upload, -1 means unknown */ + long low_speed_limit; /* bytes/second */ + long low_speed_time; /* number of seconds */ + curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ + curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */ + curl_off_t set_resume_from; /* continue [ftp] transfer from here */ + char *cookie; /* HTTP cookie string to send */ + struct curl_slist *headers; /* linked list of extra headers */ + struct curl_httppost *httppost; /* linked list of POST data */ + char *cert; /* certificate */ + char *cert_type; /* format for certificate (default: PEM) */ + char *key; /* private key */ + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ + char *cookiejar; /* dump all cookies to this file */ + bool cookiesession; /* new cookie session? */ + bool crlf; /* convert crlf on ftp upload(?) */ + char *ftp_account; /* ftp account data */ + char *ftp_alternative_to_user; /* command to send if USER/PASS fails */ + struct curl_slist *quote; /* after connection is established */ + struct curl_slist *postquote; /* after the transfer */ + struct curl_slist *prequote; /* before the transfer, after type */ + struct curl_slist *source_quote; /* 3rd party quote */ + struct curl_slist *source_prequote; /* in 3rd party transfer mode - before + the transfer on source host */ + struct curl_slist *source_postquote; /* in 3rd party transfer mode - after + the transfer on source host */ + struct curl_slist *telnet_options; /* linked list of telnet options */ + curl_TimeCond timecondition; /* kind of time/date comparison */ + time_t timevalue; /* what time to compare with */ + Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ + char *customrequest; /* HTTP/FTP request to use */ + long httpversion; /* when non-zero, a specific HTTP version requested to + be used in the library's request(s) */ + char *auth_host; /* if set, this is the allocated string to the host name + * to which to send the authorization data to, and no other + * host (which location-following otherwise could lead to) + */ + char *krb4_level; /* what security level */ + struct ssl_config_data ssl; /* user defined SSL stuff */ + + curl_proxytype proxytype; /* what kind of proxy that is in use */ + + int dns_cache_timeout; /* DNS cache timeout */ + long buffer_size; /* size of receive buffer to use */ + + char *private_data; /* Private data */ + + struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi + handle, an internal 'Curl_one_easy' + struct is created and this is a pointer + to the particular struct associated with + this SessionHandle */ + + struct curl_slist *http200aliases; /* linked list of aliases for http200 */ + + long ip_version; + + curl_off_t max_filesize; /* Maximum file size to download */ + + char *source_url; /* for 3rd party transfer */ + char *source_userpwd; /* for 3rd party transfer */ + + curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ + +/* 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 don't change during operations. */ + + bool printhost; /* printing host name in debug info */ + bool get_filetime; + bool tunnel_thru_httpproxy; + bool prefer_ascii; /* ASCII rather than binary */ + bool ftp_append; + bool ftp_list_only; + bool ftp_create_missing_dirs; + bool ftp_use_port; + bool hide_progress; + bool http_fail_on_error; + bool http_follow_location; + bool http_disable_hostname_check_before_authentication; + bool include_header; /* include received protocol headers in data output */ + bool http_set_referer; + bool http_auto_referer; /* set "correct" referer when following location: */ + bool opt_no_body; /* as set with CURLOPT_NO_BODY */ + bool set_port; + bool upload; + enum CURL_NETRC_OPTION + use_netrc; /* defined in include/curl.h */ + char *netrc_file; /* if not NULL, use this instead of trying to find + $HOME/.netrc */ + bool verbose; + bool krb4; /* kerberos4 connection requested */ + bool reuse_forbid; /* forbidden to be reused, close after use */ + bool reuse_fresh; /* do not re-use an existing connection */ + bool ftp_use_epsv; /* if EPSV is to be attempted or not */ + bool ftp_use_eprt; /* if EPRT is to be attempted or not */ + bool ftp_use_ccc; /* if CCC is to be attempted or not */ + + curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */ + curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ + bool no_signal; /* do not use any signal/alarm handler */ + bool global_dns_cache; /* subject for future removal */ + bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */ + bool ignorecl; /* ignore content length */ + bool ftp_skip_ip; /* skip the IP address the FTP server passes on to + us */ + bool connect_only; /* make connection, let application use the socket */ + long ssh_auth_types; /* allowed SSH auth types */ + char *ssh_public_key; /* the path to the public key file for + authentication */ + char *ssh_private_key; /* the path to the private key file for + authentication */ +}; + +struct Names { + struct curl_hash *hostcache; + enum { + HCACHE_NONE, /* not pointing to anything */ + HCACHE_PRIVATE, /* points to our own */ + HCACHE_GLOBAL, /* points to the (shrug) global one */ + HCACHE_MULTI, /* points to a shared one in the multi handle */ + HCACHE_SHARED /* points to a shared one in a shared object */ + } hostcachetype; +}; + +/* + * The 'connectdata' struct MUST have all the connection oriented stuff as we + * may have several simultaneous connections and connection structs in memory. + * + * The 'struct UserDefined' must only contain data that is set once to go for + * many (perhaps) independent connections. Values that are generated or + * calculated internally for the "session handle" must be defined within the + * 'struct UrlState' instead. + */ + +struct SessionHandle { + struct Names dns; + struct Curl_multi *multi; /* if non-NULL, points to the multi handle + struct to which this "belongs" */ + struct Curl_share *share; /* Share, handles global variable mutexing */ + struct HandleData reqdata; /* Request-specific data */ + struct UserDefined set; /* values set by the libcurl user */ + struct DynamicStatic change; /* possibly modified userdefined data */ + + struct CookieInfo *cookies; /* the cookies, read from files and servers */ + struct Progress progress; /* for all the progress meter data */ + struct UrlState state; /* struct for fields used for state info and + other dynamic purposes */ + struct PureInfo info; /* stats, reports and info data */ +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) + iconv_t outbound_cd; /* for translating to the network encoding */ + iconv_t inbound_cd; /* for translating from the network encoding */ + iconv_t utf8_cd; /* for translating to UTF8 */ +#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ + unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */ +}; + +#define LIBCURL_NAME "libcurl" + +#endif diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c new file mode 100644 index 0000000..9085f7d --- /dev/null +++ b/Utilities/cmcurl/lib/version.c @@ -0,0 +1,249 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#include +#include + +#include +#include "urldata.h" +#include "sslgen.h" + +#define _MPRINTF_REPLACE /* use the internal *printf() functions */ +#include + +#ifdef USE_ARES +#include +#endif + +#ifdef USE_LIBIDN +#include +#endif + +#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) +#include +#endif + +#ifdef USE_LIBSSH2 +#include +#endif + + +char *curl_version(void) +{ + static char version[200]; + char *ptr=version; + size_t len; + size_t left = sizeof(version); + strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION ); + ptr=strchr(ptr, '\0'); + left -= strlen(ptr); + + len = Curl_ssl_version(ptr, left); + left -= len; + ptr += len; + +#ifdef HAVE_LIBZ + len = snprintf(ptr, left, " zlib/%s", zlibVersion()); + left -= len; + ptr += len; +#endif +#ifdef USE_ARES + /* this function is only present in c-ares, not in the original ares */ + len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL)); + left -= len; + ptr += len; +#endif +#ifdef USE_LIBIDN + if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { + len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL)); + left -= len; + ptr += len; + } +#endif +#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) +#ifdef _LIBICONV_VERSION + len = snprintf(ptr, left, " iconv/%d.%d", + _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); +#else + /* version unknown */ + len = snprintf(ptr, left, " iconv"); +#endif /* _LIBICONV_VERSION */ + left -= len; + ptr += len; +#endif +#ifdef USE_LIBSSH2 + len = snprintf(ptr, left, " libssh2/%s", LIBSSH2_VERSION); + left -= len; + ptr += len; +#endif + + return version; +} + +/* data for curl_version_info */ + +static const char * const protocols[] = { +#ifndef CURL_DISABLE_TFTP + "tftp", +#endif +#ifndef CURL_DISABLE_FTP + "ftp", +#endif +#ifndef CURL_DISABLE_TELNET + "telnet", +#endif +#ifndef CURL_DISABLE_DICT + "dict", +#endif +#ifndef CURL_DISABLE_LDAP + "ldap", +#endif +#ifndef CURL_DISABLE_HTTP + "http", +#endif +#ifndef CURL_DISABLE_FILE + "file", +#endif + +#ifdef USE_SSL +#ifndef CURL_DISABLE_HTTP + "https", +#endif +#ifndef CURL_DISABLE_FTP + "ftps", +#endif +#endif + +#ifdef USE_LIBSSH2 + "scp", + "sftp", +#endif + + NULL +}; + +static curl_version_info_data version_info = { + CURLVERSION_NOW, + LIBCURL_VERSION, + LIBCURL_VERSION_NUM, + OS, /* as found by configure or set by hand at build-time */ + 0 /* features is 0 by default */ +#ifdef ENABLE_IPV6 + | CURL_VERSION_IPV6 +#endif +#ifdef HAVE_KRB4 + | CURL_VERSION_KERBEROS4 +#endif +#ifdef USE_SSL + | CURL_VERSION_SSL +#endif +#ifdef USE_NTLM + | CURL_VERSION_NTLM +#endif +#ifdef USE_WINDOWS_SSPI + | CURL_VERSION_SSPI +#endif +#ifdef HAVE_LIBZ + | CURL_VERSION_LIBZ +#endif +#ifdef HAVE_GSSAPI + | CURL_VERSION_GSSNEGOTIATE +#endif +#ifdef CURLDEBUG + | CURL_VERSION_DEBUG +#endif +#ifdef USE_ARES + | CURL_VERSION_ASYNCHDNS +#endif +#ifdef HAVE_SPNEGO + | CURL_VERSION_SPNEGO +#endif +#if defined(ENABLE_64BIT) && (SIZEOF_CURL_OFF_T > 4) + | CURL_VERSION_LARGEFILE +#endif +#if defined(CURL_DOES_CONVERSIONS) + | CURL_VERSION_CONV +#endif + , + NULL, /* ssl_version */ + 0, /* ssl_version_num, this is kept at zero */ + NULL, /* zlib_version */ + protocols, + NULL, /* c-ares version */ + 0, /* c-ares version numerical */ + NULL, /* libidn version */ + 0, /* iconv version */ + NULL, /* ssh lib version */ +}; + +curl_version_info_data *curl_version_info(CURLversion stamp) +{ +#ifdef USE_LIBSSH2 + static char ssh_buffer[80]; +#endif + +#ifdef USE_SSL + static char ssl_buffer[80]; + Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); + version_info.ssl_version = ssl_buffer; +#endif + +#ifdef HAVE_LIBZ + version_info.libz_version = zlibVersion(); + /* libz left NULL if non-existing */ +#endif +#ifdef USE_ARES + { + int aresnum; + version_info.ares = ares_version(&aresnum); + version_info.ares_num = aresnum; + } +#endif +#ifdef USE_LIBIDN + /* This returns a version string if we use the given version or later, + otherwise it returns NULL */ + version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION); + if(version_info.libidn) + version_info.features |= CURL_VERSION_IDN; +#endif + +#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) +#ifdef _LIBICONV_VERSION + version_info.iconv_ver_num = _LIBICONV_VERSION; +#else + /* version unknown */ + version_info.iconv_ver_num = -1; +#endif /* _LIBICONV_VERSION */ +#endif + +#ifdef USE_LIBSSH2 + snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION); + version_info.libssh_version = ssh_buffer; +#endif + + (void)stamp; /* avoid compiler warnings, we don't use this */ + + return &version_info; +} diff --git a/Utilities/cmcurl/llist.c b/Utilities/cmcurl/llist.c deleted file mode 100644 index 921d1d1..0000000 --- a/Utilities/cmcurl/llist.c +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#include "llist.h" -#include "memory.h" - -/* this must be the last include file */ -#include "memdebug.h" - -void -Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor) -{ - l->size = 0; - l->dtor = dtor; - l->head = NULL; - l->tail = NULL; -} - -struct curl_llist * -Curl_llist_alloc(curl_llist_dtor dtor) -{ - struct curl_llist *list; - - list = (struct curl_llist *)malloc(sizeof(struct curl_llist)); - if(NULL == list) - return NULL; - - Curl_llist_init(list, dtor); - - return list; -} - -/* - * Curl_llist_insert_next() returns 1 on success and 0 on failure. - */ -int -Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, - const void *p) -{ - struct curl_llist_element *ne = - (struct curl_llist_element *) malloc(sizeof(struct curl_llist_element)); - if(!ne) - return 0; - - ne->ptr = (void *) p; - if (list->size == 0) { - list->head = ne; - list->head->prev = NULL; - list->head->next = NULL; - list->tail = ne; - } - else { - ne->next = e->next; - ne->prev = e; - if (e->next) { - e->next->prev = ne; - } - else { - list->tail = ne; - } - e->next = ne; - } - - ++list->size; - - return 1; -} - -int -Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, - void *user) -{ - if (e == NULL || list->size == 0) - return 1; - - if (e == list->head) { - list->head = e->next; - - if (list->head == NULL) - list->tail = NULL; - else - e->next->prev = NULL; - } else { - e->prev->next = e->next; - if (!e->next) - list->tail = e->prev; - else - e->next->prev = e->prev; - } - - list->dtor(user, e->ptr); - free(e); - --list->size; - - return 1; -} - -void -Curl_llist_destroy(struct curl_llist *list, void *user) -{ - if(list) { - while (list->size > 0) - Curl_llist_remove(list, list->tail, user); - - free(list); - } -} - -size_t -Curl_llist_count(struct curl_llist *list) -{ - return list->size; -} diff --git a/Utilities/cmcurl/llist.h b/Utilities/cmcurl/llist.h deleted file mode 100644 index 5c7a8a0..0000000 --- a/Utilities/cmcurl/llist.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __LLIST_H -#define __LLIST_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include - -typedef void (*curl_llist_dtor)(void *, void *); - -struct curl_llist_element { - void *ptr; - - struct curl_llist_element *prev; - struct curl_llist_element *next; -}; - -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); -struct curl_llist *Curl_llist_alloc(curl_llist_dtor); -int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *, - const void *); -int Curl_llist_insert_prev(struct curl_llist *, struct curl_llist_element *, - const void *); -int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, - void *); -int Curl_llist_remove_next(struct curl_llist *, struct curl_llist_element *, - void *); -size_t Curl_llist_count(struct curl_llist *); -void Curl_llist_destroy(struct curl_llist *, void *); - -#endif diff --git a/Utilities/cmcurl/md5.c b/Utilities/cmcurl/md5.c deleted file mode 100644 index 4cfb073..0000000 --- a/Utilities/cmcurl/md5.c +++ /dev/null @@ -1,352 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_CRYPTO_AUTH - -#if !defined(USE_SSLEAY) || !defined(USE_OPENSSL) -/* This code segment is only used if OpenSSL is not provided, as if it is - we use the MD5-function provided there instead. No good duplicating - code! */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -#include - -/* UINT4 defines a four byte word */ -typedef unsigned int UINT4; - -/* MD5 context. */ -struct md5_ctx { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -}; - -typedef struct md5_ctx MD5_CTX; - -static void MD5_Init(struct md5_ctx *); -static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int); -static void MD5_Final(unsigned char [16], struct md5_ctx *); - -/* Constants for MD5Transform routine. - */ - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform(UINT4 [4], const unsigned char [64]); -static void Encode(unsigned char *, UINT4 *, unsigned int); -static void Decode(UINT4 *, const unsigned char *, unsigned int); - -static const unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -static void MD5_Init(struct md5_ctx *context) -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -static void MD5_Update (struct md5_ctx *context, /* context */ - const unsigned char *input, /* input block */ - unsigned int inputLen) /* length of input block */ -{ - unsigned int i, bufindex, partLen; - - /* Compute number of bytes mod 64 */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - bufindex; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) { - memcpy((void *)&context->buffer[bufindex], (void *)input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); - - bufindex = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy((void *)&context->buffer[bufindex], (void *)&input[i], inputLen-i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. -*/ -static void MD5_Final(unsigned char digest[16], /* message digest */ - struct md5_ctx *context) /* context */ -{ - unsigned char bits[8]; - unsigned int count, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. */ - count = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (count < 56) ? (56 - count) : (120 - count); - MD5_Update (context, PADDING, padLen); - - /* Append length (before padding) */ - MD5_Update (context, bits, 8); - - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. */ - memset ((void *)context, 0, sizeof (*context)); -} - -/* MD5 basic transformation. Transforms state based on block. */ -static void MD5Transform(UINT4 state[4], - const unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset((void *)x, 0, sizeof (x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode (unsigned char *output, - UINT4 *input, - unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. -*/ -static void Decode (UINT4 *output, - const unsigned char *input, - unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); -} - -#else -/* If OpenSSL is present */ -#include -#include -#endif - -#include "md5.h" - -void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */ - const unsigned char *input) -{ - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, input, (unsigned int)strlen((char *)input)); - MD5_Final(outbuffer, &ctx); -} - -#endif diff --git a/Utilities/cmcurl/md5.h b/Utilities/cmcurl/md5.h deleted file mode 100644 index 63cc70e..0000000 --- a/Utilities/cmcurl/md5.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __MD5_H -#define __MD5_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -void Curl_md5it(unsigned char *output, - const unsigned char *input); - -#endif diff --git a/Utilities/cmcurl/memdebug.c b/Utilities/cmcurl/memdebug.c deleted file mode 100644 index a8cca44..0000000 --- a/Utilities/cmcurl/memdebug.c +++ /dev/null @@ -1,298 +0,0 @@ -#ifdef CURLDEBUG -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#define _MPRINTF_REPLACE -#include -#include "urldata.h" -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ -#include "memory.h" -#include "memdebug.h" - -struct memdebug { - size_t size; - double mem[1]; - /* I'm hoping this is the thing with the strictest alignment - * requirements. That also means we waste some space :-( */ -}; - -/* - * Note that these debug functions are very simple and they are meant to - * remain so. For advanced analysis, record a log file and write perl scripts - * to analyze them! - * - * Don't use these with multithreaded test programs! - */ - -#define logfile curl_debuglogfile -FILE *curl_debuglogfile = NULL; -static bool memlimit = FALSE; /* enable memory limit */ -static long memsize = 0; /* set number of mallocs allowed */ - -/* this sets the log file name */ -void curl_memdebug(const char *logname) -{ - if (!logfile) { - if(logname) - logfile = fopen(logname, "w"); - else - logfile = stderr; - } -} - -/* This function sets the number of malloc() calls that should return - successfully! */ -void curl_memlimit(long limit) -{ - if (!memlimit) { - memlimit = TRUE; - memsize = limit; - } -} - -/* 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 - should not be made */ - if(memlimit && source) { - if(!memsize) { - if(logfile && source) - fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n", - source, line, func); - if(source) - fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", - source, line, func); - errno = ENOMEM; - return TRUE; /* RETURN ERROR! */ - } - else - memsize--; /* countdown */ - - /* log the countdown */ - if(logfile && source) - fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n", - source, line, memsize); - - } - - return FALSE; /* allow this */ -} - -void *curl_domalloc(size_t wantedsize, int line, const char *source) -{ - struct memdebug *mem; - size_t size; - - if(countcheck("malloc", line, source)) - return NULL; - - /* alloc at least 64 bytes */ - size = sizeof(struct memdebug)+wantedsize; - - mem=(struct memdebug *)(Curl_cmalloc)(size); - if(mem) { - /* fill memory with junk */ - memset(mem->mem, 0xA5, wantedsize); - mem->size = wantedsize; - } - - if(logfile && source) - fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n", - source, line, wantedsize, mem ? mem->mem : 0); - return (mem ? mem->mem : NULL); -} - -void *curl_docalloc(size_t wanted_elements, size_t wanted_size, - int line, const char *source) -{ - struct memdebug *mem; - size_t size, user_size; - - if(countcheck("calloc", line, source)) - return NULL; - - /* alloc at least 64 bytes */ - user_size = wanted_size * wanted_elements; - size = sizeof(struct memdebug) + user_size; - - mem = (struct memdebug *)(Curl_cmalloc)(size); - if(mem) { - /* fill memory with zeroes */ - memset(mem->mem, 0, user_size); - mem->size = user_size; - } - - if(logfile && source) - fprintf(logfile, "MEM %s:%d calloc(%u,%u) = %p\n", - source, line, wanted_elements, wanted_size, mem ? mem->mem : 0); - return (mem ? mem->mem : NULL); -} - -char *curl_dostrdup(const char *str, int line, const char *source) -{ - char *mem; - size_t len; - - curlassert(str != NULL); - - if(countcheck("strdup", line, source)) - return NULL; - - len=strlen(str)+1; - - mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */ - if (mem) - memcpy(mem, str, len); - - if(logfile) - fprintf(logfile, "MEM %s:%d strdup(%p) (%zd) = %p\n", - source, line, str, len, mem); - - return mem; -} - -/* We provide a realloc() that accepts a NULL as pointer, which then - performs a malloc(). In order to work with ares. */ -void *curl_dorealloc(void *ptr, size_t wantedsize, - int line, const char *source) -{ - struct memdebug *mem=NULL; - - size_t size = sizeof(struct memdebug)+wantedsize; - - if(countcheck("realloc", line, source)) - return NULL; - - if(ptr) - mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem)); - - mem=(struct memdebug *)(Curl_crealloc)(mem, size); - if(logfile) - fprintf(logfile, "MEM %s:%d realloc(%p, %zd) = %p\n", - source, line, ptr, wantedsize, mem?mem->mem:NULL); - - if(mem) { - mem->size = wantedsize; - return mem->mem; - } - - return NULL; -} - -void curl_dofree(void *ptr, int line, const char *source) -{ - struct memdebug *mem; - - curlassert(ptr != NULL); - - mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem)); - - /* destroy */ - memset(mem->mem, 0x13, mem->size); - - /* free for real */ - (Curl_cfree)(mem); - - if(logfile) - fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr); -} - -int curl_socket(int domain, int type, int protocol, int line, - const char *source) -{ - int sockfd=(socket)(domain, type, protocol); - if(logfile && (sockfd!=-1)) - fprintf(logfile, "FD %s:%d socket() = %d\n", - source, line, sockfd); - return sockfd; -} - -int curl_accept(int s, void *saddr, void *saddrlen, - int line, const char *source) -{ - struct sockaddr *addr = (struct sockaddr *)saddr; - socklen_t *addrlen = (socklen_t *)saddrlen; - int sockfd=(accept)(s, addr, addrlen); - if(logfile) - fprintf(logfile, "FD %s:%d accept() = %d\n", - source, line, sockfd); - return sockfd; -} - -/* this is our own defined way to close sockets on *ALL* platforms */ -int curl_sclose(int sockfd, int line, const char *source) -{ - int res=sclose(sockfd); - if(logfile) - fprintf(logfile, "FD %s:%d sclose(%d)\n", - source, line, sockfd); - return res; -} - -FILE *curl_fopen(const char *file, const char *mode, - int line, const char *source) -{ - FILE *res=(fopen)(file, mode); - if(logfile) - fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", - source, line, file, mode, res); - return res; -} - -int curl_fclose(FILE *file, int line, const char *source) -{ - int res; - - curlassert(file != NULL); - - res=(fclose)(file); - if(logfile) - fprintf(logfile, "FILE %s:%d fclose(%p)\n", - source, line, file); - return res; -} -#else -#ifdef VMS -int VOID_VAR_MEMDEBUG; -#else -/* we provide a fake do-nothing function here to avoid compiler warnings */ -void curl_memdebug(void) {} -#endif /* VMS */ -#endif /* CURLDEBUG */ diff --git a/Utilities/cmcurl/memdebug.h b/Utilities/cmcurl/memdebug.h deleted file mode 100644 index a4ce7e5..0000000 --- a/Utilities/cmcurl/memdebug.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifdef CURLDEBUG -#ifndef _CURL_MEDEBUG_H -#define _CURL_MEDEBUG_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * CAUTION: this header is designed to work when included by the app-side - * as well as the library. Do not mix with library internals! - */ - -#include "setup.h" - -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_MEMORY_H -#include -#endif - -#define logfile curl_debuglogfile - -extern FILE *logfile; - -/* memory functions */ -CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source); -CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, const char *source); -CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, const char *source); -CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source); -CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source); -CURL_EXTERN void curl_memdebug(const char *logname); -CURL_EXTERN void curl_memlimit(long limit); - -/* file descriptor manipulators */ -CURL_EXTERN int curl_socket(int domain, int type, int protocol, int line , const char *); -CURL_EXTERN int curl_sclose(int sockfd, int, const char *source); -CURL_EXTERN int curl_accept(int s, void *addr, void *addrlen, - int line, const char *source); - -/* FILE functions */ -CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line, - const char *source); -CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); - -#ifndef MEMDEBUG_NODEFINES - -/* Set this symbol on the command-line, recompile all lib-sources */ -#undef strdup -#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__) -#define malloc(size) curl_domalloc(size, __LINE__, __FILE__) -#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__) -#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__) -#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__) - -#define socket(domain,type,protocol)\ - curl_socket(domain,type,protocol,__LINE__,__FILE__) -#undef accept /* for those with accept as a macro */ -#define accept(sock,addr,len)\ - curl_accept(sock,addr,len,__LINE__,__FILE__) - -#if defined(getaddrinfo) && defined(__osf__) -/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define - our macro as for other platforms. Instead, we redefine the new name they - define getaddrinfo to become! */ -#define ogetaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) -#else -#undef getaddrinfo -#define getaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) -#endif - -#ifdef HAVE_GETNAMEINFO -#undef getnameinfo -#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \ - curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \ - __FILE__) -#endif - -#undef freeaddrinfo -#define freeaddrinfo(data) \ - curl_dofreeaddrinfo(data,__LINE__,__FILE__) - -/* sclose is probably already defined, redefine it! */ -#undef sclose -#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__) -/* ares-adjusted define: */ -#undef closesocket -#define closesocket(sockfd) curl_sclose(sockfd,__LINE__,__FILE__) - -#undef fopen -#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__) -#define fclose(file) curl_fclose(file,__LINE__,__FILE__) - -#endif /* MEMDEBUG_NODEFINES */ - -#endif /* _CURL_MEDEBUG_H */ -#endif /* CURLDEBUG */ diff --git a/Utilities/cmcurl/memory.h b/Utilities/cmcurl/memory.h deleted file mode 100644 index 076d20a..0000000 --- a/Utilities/cmcurl/memory.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _CURL_MEMORY_H -#define _CURL_MEMORY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include /* for the typedefs */ - -extern curl_malloc_callback Curl_cmalloc; -extern curl_free_callback Curl_cfree; -extern curl_realloc_callback Curl_crealloc; -extern curl_strdup_callback Curl_cstrdup; -extern curl_calloc_callback Curl_ccalloc; - -#ifndef CURLDEBUG -/* Only do this define-mania if we're not using the memdebug system, as that - has preference on this magic. */ -#undef strdup -#define strdup(ptr) Curl_cstrdup(ptr) -#undef malloc -#define malloc(size) Curl_cmalloc(size) -#undef calloc -#define calloc(nbelem,size) Curl_ccalloc(nbelem, size) -#undef realloc -#define realloc(ptr,size) Curl_crealloc(ptr, size) -#undef free -#define free(ptr) Curl_cfree(ptr) - -#endif - -#endif /* _CURL_MEMORY_H */ diff --git a/Utilities/cmcurl/mprintf.c b/Utilities/cmcurl/mprintf.c deleted file mode 100644 index 8b2f3d0..0000000 --- a/Utilities/cmcurl/mprintf.c +++ /dev/null @@ -1,1218 +0,0 @@ -/**************************************************************************** - * - * $Id$ - * - ************************************************************************* - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND - * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. - * - * Purpose: - * A merge of Bjorn Reese's format() function and Daniel's dsprintf() - * 1.0. A full blooded printf() clone with full support for $ - * 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 http://daniel.haxx.se/trio/ - */ - - -#include "setup.h" -#include -#include -#include -#include -#include -#include - -#if defined(DJGPP) && (DJGPP_MINOR < 4) -#undef _MPRINTF_REPLACE /* don't use x_was_used() here */ -#endif - -#include - -#ifndef SIZEOF_SIZE_T -/* default to 4 bytes for size_t unless defined in the config.h */ -#define SIZEOF_SIZE_T 4 -#endif - -#ifdef DPRINTF_DEBUG -#define HAVE_LONGLONG -#define LONG_LONG long long -#define ENABLE_64BIT -#endif - -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ -#define MAX_PARAMETERS 128 /* lame static limit */ - -#undef TRUE -#undef FALSE -#undef BOOL -#ifdef __cplusplus -# define TRUE true -# define FALSE false -# define BOOL bool -#else -# define TRUE ((char)(1 == 1)) -# define FALSE ((char)(0 == 1)) -# define BOOL char -#endif - -#ifdef _AMIGASF -# undef FORMAT_INT -#endif - -/* Lower-case digits. */ -static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - -/* Upper-case digits. */ -static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -#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_INT, - FORMAT_INTPTR, - FORMAT_LONG, - FORMAT_LONGLONG, - FORMAT_DOUBLE, - FORMAT_LONGDOUBLE, - FORMAT_WIDTH /* For internal use */ -} FormatType; - -/* convertion and display flags */ -enum { - FLAGS_NEW = 0, - FLAGS_SPACE = 1<<0, - FLAGS_SHOWSIGN = 1<<1, - FLAGS_LEFT = 1<<2, - FLAGS_ALT = 1<<3, - FLAGS_SHORT = 1<<4, - FLAGS_LONG = 1<<5, - FLAGS_LONGLONG = 1<<6, - FLAGS_LONGDOUBLE = 1<<7, - FLAGS_PAD_NIL = 1<<8, - FLAGS_UNSIGNED = 1<<9, - FLAGS_OCTAL = 1<<10, - FLAGS_HEX = 1<<11, - FLAGS_UPPER = 1<<12, - FLAGS_WIDTH = 1<<13, /* '*' or '*$' used */ - FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ - FLAGS_PREC = 1<<15, /* precision was specified */ - 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 */ -}; - -typedef struct { - FormatType type; - int flags; - long width; /* width OR width parameter number */ - long precision; /* precision OR precision parameter number */ - union { - char *str; - void *ptr; - long num; -#ifdef ENABLE_64BIT - LONG_LONG lnum; -#endif - double dnum; - } data; -} va_stack_t; - -struct nsprintf { - char *buffer; - size_t length; - size_t max; -}; - -struct asprintf { - char *buffer; /* allocated buffer */ - size_t len; /* length of string */ - size_t alloc; /* length of alloc */ - bool fail; /* TRUE if an alloc has failed and thus the output is not - the complete data */ -}; - -int curl_msprintf(char *buffer, const char *format, ...); - -static long dprintf_DollarString(char *input, char **end) -{ - int number=0; - while(ISDIGIT(*input)) { - number *= 10; - number += *input-'0'; - input++; - } - if(number && ('$'==*input++)) { - *end = input; - return number; - } - return 0; -} - -static BOOL dprintf_IsQualifierNoDollar(char c) -{ - switch (c) { - 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': - return TRUE; - default: - return FALSE; - } -} - -#ifdef DPRINTF_DEBUG2 -int dprintf_Pass1Report(va_stack_t *vto, int max) -{ - int i; - char buffer[128]; - int bit; - int flags; - - for(i=0; i 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)) { - switch (*fmt++) { - case ' ': - flags |= FLAGS_SPACE; - break; - case '+': - flags |= FLAGS_SHOWSIGN; - break; - case '-': - flags |= FLAGS_LEFT; - flags &= ~FLAGS_PAD_NIL; - break; - case '#': - flags |= FLAGS_ALT; - break; - case '.': - flags |= FLAGS_PREC; - if ('*' == *fmt) { - /* The precision is picked from a specified parameter */ - - flags |= FLAGS_PRECPARAM; - fmt++; - param_num++; - - i = dprintf_DollarString(fmt, &fmt); - if (i) - precision = i; - else - precision = param_num; - - if (precision > max_param) - max_param = precision; - } - else { - flags |= FLAGS_PREC; - precision = strtol(fmt, &fmt, 10); - } - break; - case 'h': - flags |= FLAGS_SHORT; - break; - case 'l': - if (flags & FLAGS_LONG) - flags |= FLAGS_LONGLONG; - else - flags |= FLAGS_LONG; - break; - case 'L': - flags |= FLAGS_LONGDOUBLE; - break; - case 'q': - flags |= FLAGS_LONGLONG; - break; - case 'z': - /* the code below generates a warning if -Wunreachable-code is - used */ -#if SIZEOF_SIZE_T>4 - flags |= FLAGS_LONGLONG; -#else - flags |= FLAGS_LONG; -#endif - break; - case 'O': -#if SIZEOF_CURL_OFF_T > 4 - flags |= FLAGS_LONGLONG; -#else - flags |= FLAGS_LONG; -#endif - break; - case '0': - if (!(flags & FLAGS_LEFT)) - flags |= FLAGS_PAD_NIL; - /* FALLTHROUGH */ - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - flags |= FLAGS_WIDTH; - width = strtol(fmt-1, &fmt, 10); - break; - case '*': /* Special case */ - flags |= FLAGS_WIDTHPARAM; - param_num++; - - i = dprintf_DollarString(fmt, &fmt); - if(i) - width = i; - else - width = param_num; - if(width > max_param) - max_param=width; - break; - default: - break; - } - } /* switch */ - - /* Handle the specifier */ - - i = this_param - 1; - - switch (*fmt) { - case 'S': - flags |= FLAGS_ALT; - /* FALLTHROUGH */ - case 's': - vto[i].type = FORMAT_STRING; - break; - case 'n': - vto[i].type = FORMAT_INTPTR; - break; - case 'p': - vto[i].type = FORMAT_PTR; - break; - case 'd': case 'i': - vto[i].type = FORMAT_INT; - break; - case 'u': - vto[i].type = FORMAT_INT; - flags |= FLAGS_UNSIGNED; - break; - case 'o': - vto[i].type = FORMAT_INT; - flags |= FLAGS_OCTAL; - break; - case 'x': - vto[i].type = FORMAT_INT; - flags |= FLAGS_HEX; - break; - case 'X': - vto[i].type = FORMAT_INT; - flags |= FLAGS_HEX|FLAGS_UPPER; - break; - case 'c': - vto[i].type = FORMAT_INT; - flags |= FLAGS_CHAR; - break; - case 'f': - vto[i].type = FORMAT_DOUBLE; - break; - case 'e': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATE; - break; - case 'E': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATE|FLAGS_UPPER; - break; - case 'g': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATG; - break; - case 'G': - vto[i].type = FORMAT_DOUBLE; - flags |= FLAGS_FLOATG|FLAGS_UPPER; - break; - default: - vto[i].type = FORMAT_UNKNOWN; - break; - } /* switch */ - - vto[i].flags = flags; - vto[i].width = width; - vto[i].precision = precision; - - if (flags & FLAGS_WIDTHPARAM) { - /* we have the width specified from a parameter, so we make that - parameter's info setup properly */ - vto[i].width = width - 1; - i = width - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ - } - if (flags & FLAGS_PRECPARAM) { - /* we have the precision specified from a parameter, so we make that - parameter's info setup properly */ - vto[i].precision = precision - 1; - i = precision - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ - } - *endpos++ = fmt + 1; /* end of this sequence */ - } - } - -#ifdef DPRINTF_DEBUG2 - dprintf_Pass1Report(vto, max_param); -#endif - - /* Read the arg list parameters into our data list */ - for (i=0; i$ 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(p->flags & FLAGS_WIDTHPARAM) - width = vto[p->width].data.num; - else - width = p->width; - - /* pick up the specified precision */ - if(p->flags & FLAGS_PRECPARAM) - prec = vto[p->precision].data.num; - else if(p->flags & FLAGS_PREC) - prec = p->precision; - else - prec = -1; - - alt = (p->flags & FLAGS_ALT)?TRUE:FALSE; - - switch (p->type) { - case FORMAT_INT: - num = p->data.num; - if(p->flags & FLAGS_CHAR) { - /* Character. */ - if (!(p->flags & FLAGS_LEFT)) - while (--width > 0) - OUTCHAR(' '); - OUTCHAR((char) num); - if (p->flags & FLAGS_LEFT) - while (--width > 0) - OUTCHAR(' '); - break; - } - if(p->flags & FLAGS_UNSIGNED) { - /* Decimal unsigned integer. */ - base = 10; - goto unsigned_number; - } - if(p->flags & FLAGS_OCTAL) { - /* Octal unsigned integer. */ - base = 8; - goto unsigned_number; - } - if(p->flags & FLAGS_HEX) { - /* Hexadecimal unsigned integer. */ - - digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; - base = 16; - goto unsigned_number; - } - - /* Decimal integer. */ - base = 10; - -#ifdef ENABLE_64BIT - if(p->flags & FLAGS_LONGLONG) { - /* long long */ - is_neg = p->data.lnum < 0; - num = is_neg ? (- p->data.lnum) : p->data.lnum; - } - else -#endif - { - signed_num = (long) num; - is_neg = signed_num < 0; - num = is_neg ? (- signed_num) : signed_num; - } - goto number; - - unsigned_number: - /* Unsigned number of base BASE. */ - is_neg = 0; - - number: - /* Number of base BASE. */ - { - char *workend = &work[sizeof(work) - 1]; - char *w; - - /* Supply a default precision if none was given. */ - if (prec == -1) - prec = 1; - - /* Put the number in WORK. */ - w = workend; - while (num > 0) { - *w-- = digits[num % base]; - num /= base; - } - width -= (long)(workend - w); - prec -= (long)(workend - w); - - if (alt && base == 8 && prec <= 0) { - *w-- = '0'; - --width; - } - - if (prec > 0) { - width -= prec; - while (prec-- > 0) - *w-- = '0'; - } - - if (alt && base == 16) - width -= 2; - - if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) - --width; - - if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) - while (width-- > 0) - OUTCHAR(' '); - - if (is_neg) - OUTCHAR('-'); - else if (p->flags & FLAGS_SHOWSIGN) - OUTCHAR('+'); - else if (p->flags & FLAGS_SPACE) - OUTCHAR(' '); - - if (alt && base == 16) { - OUTCHAR('0'); - if(p->flags & FLAGS_UPPER) - OUTCHAR('X'); - else - OUTCHAR('x'); - } - - if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) - while (width-- > 0) - OUTCHAR('0'); - - /* Write the number. */ - while (++w <= workend) { - OUTCHAR(*w); - } - - if (p->flags & FLAGS_LEFT) - while (width-- > 0) - OUTCHAR(' '); - } - break; - - case FORMAT_STRING: - /* String. */ - { - static const char null[] = "(nil)"; - const char *str; - size_t len; - - str = (char *) p->data.str; - if ( str == NULL) { - /* 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 - len = strlen(str); - - if (prec != -1 && (size_t) prec < len) - len = prec; - width -= (long)len; - - if (p->flags & FLAGS_ALT) - OUTCHAR('"'); - - if (!(p->flags&FLAGS_LEFT)) - while (width-- > 0) - OUTCHAR(' '); - - while (len-- > 0) - OUTCHAR(*str++); - if (p->flags&FLAGS_LEFT) - while (width-- > 0) - OUTCHAR(' '); - - if (p->flags & FLAGS_ALT) - OUTCHAR('"'); - } - break; - - case FORMAT_PTR: - /* Generic pointer. */ - { - void *ptr; - ptr = (void *) p->data.ptr; - if (ptr != NULL) { - /* If the pointer is not NULL, write it as a %#x spec. */ - base = 16; - digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; - 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 -= 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; - 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 = vto[p->width].data.num; - - prec = -1; - if (p->flags & FLAGS_PREC) - prec = p->precision; - else if (p->flags & FLAGS_PRECPARAM) - prec = vto[p->precision].data.num; - - if (p->flags & FLAGS_LEFT) - strcat(formatbuf, "-"); - if (p->flags & FLAGS_SHOWSIGN) - strcat(formatbuf, "+"); - if (p->flags & FLAGS_SPACE) - strcat(formatbuf, " "); - if (p->flags & FLAGS_ALT) - strcat(formatbuf, "#"); - - fptr=&formatbuf[strlen(formatbuf)]; - - if(width >= 0) { - /* RECURSIVE USAGE */ - len = curl_msnprintf(fptr, left, "%ld", width); - fptr += len; - left -= len; - } - if(prec >= 0) { - /* RECURSIVE USAGE */ - len = curl_msnprintf(fptr, left, ".%ld", prec); - fptr += len; - left -= len; - } - if (p->flags & FLAGS_LONG) - *fptr++ = 'l'; - - if (p->flags & FLAGS_FLOATE) - *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e'; - else if (p->flags & FLAGS_FLOATG) - *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g'; - else - *fptr++ = 'f'; - - *fptr = 0; /* and a final zero termination */ - - /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number - of output characters */ - (sprintf)(work, formatbuf, p->data.dnum); - - for(fptr=work; *fptr; fptr++) - OUTCHAR(*fptr); - } - break; - - case FORMAT_INTPTR: - /* Answer the count of characters written. */ -#ifdef ENABLE_64BIT - if (p->flags & FLAGS_LONGLONG) - *(LONG_LONG *) p->data.ptr = (LONG_LONG)done; - else -#endif - 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 *) p->data.ptr = (short)done; - break; - - default: - break; - } - f = *end++; /* goto end of %-code */ - - } - return done; -} - -/* fputc() look-alike */ -static int addbyter(int output, FILE *data) -{ - struct nsprintf *infop=(struct nsprintf *)data; - unsigned char outc = (unsigned char)output; - - if(infop->length < infop->max) { - /* 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 outc; /* fputc() returns like this on success */ - } - return -1; -} - -int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, - va_list ap_save) -{ - int retcode; - struct nsprintf info; - - info.buffer = buffer; - info.length = 0; - info.max = maxlength; - - retcode = dprintf_formatf(&info, addbyter, format, ap_save); - if(info.max) { - /* we terminate this with a zero byte */ - if(info.max == info.length) - /* we're at maximum, scrap the last letter */ - info.buffer[-1] = 0; - else - info.buffer[0] = 0; - } - return retcode; -} - -int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) -{ - int retcode; - va_list ap_save; /* argument pointer */ - va_start(ap_save, format); - retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); - va_end(ap_save); - return retcode; -} - -/* fputc() look-alike */ -static int alloc_addbyter(int output, FILE *data) -{ - struct asprintf *infop=(struct asprintf *)data; - unsigned char outc = (unsigned char)output; - - if(!infop->buffer) { - infop->buffer=(char *)malloc(32); - if(!infop->buffer) { - infop->fail = TRUE; - return -1; /* fail */ - } - infop->alloc = 32; - infop->len =0; - } - else if(infop->len+1 >= infop->alloc) { - char *newptr; - - newptr = (char *)realloc(infop->buffer, infop->alloc*2); - - if(!newptr) { - infop->fail = TRUE; - return -1; - } - infop->buffer = newptr; - infop->alloc *= 2; - } - - infop->buffer[ infop->len ] = outc; - - infop->len++; - - return outc; /* fputc() returns like this on success */ -} - -char *curl_maprintf(const char *format, ...) -{ - va_list ap_save; /* argument pointer */ - int retcode; - struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; - info.fail = FALSE; - - va_start(ap_save, format); - retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); - va_end(ap_save); - if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); - return NULL; - } - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } - else - return strdup(""); -} - -char *curl_mvaprintf(const char *format, va_list ap_save) -{ - int retcode; - struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; - info.fail = FALSE; - - retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); - if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); - return NULL; - } - - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } - else - return strdup(""); -} - -static int storebuffer(int output, FILE *data) -{ - char **buffer = (char **)data; - unsigned char outc = (unsigned char)output; - **buffer = outc; - (*buffer)++; - return outc; /* act like fputc() ! */ -} - -int curl_msprintf(char *buffer, const char *format, ...) -{ - va_list ap_save; /* argument pointer */ - int retcode; - va_start(ap_save, format); - retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); - va_end(ap_save); - *buffer=0; /* we terminate this with a zero byte */ - return retcode; -} - -int curl_mprintf(const char *format, ...) -{ - int retcode; - va_list ap_save; /* argument pointer */ - va_start(ap_save, format); - - retcode = dprintf_formatf(stdout, fputc, format, ap_save); - va_end(ap_save); - return retcode; -} - -int curl_mfprintf(FILE *whereto, const char *format, ...) -{ - int retcode; - va_list ap_save; /* argument pointer */ - va_start(ap_save, format); - 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; - 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 dprintf_formatf(stdout, fputc, format, ap_save); -} - -int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) -{ - return dprintf_formatf(whereto, fputc, format, ap_save); -} - -#ifdef DPRINTF_DEBUG -int main() -{ - char buffer[129]; - char *ptr; -#ifdef ENABLE_64BIT - long long one=99; - long long two=100; - long long test = 0x1000000000LL; - curl_mprintf("%lld %lld %lld\n", one, two, test); -#endif - - curl_mprintf("%3d %5d\n", 10, 1998); - - ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001); - - puts(ptr); - - memset(ptr, 55, strlen(ptr)+1); - - free(ptr); - -#if 1 - curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988); - puts(buffer); - - curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65); - - printf("%s %#08x\n", "dummy", 65); - { - double tryout = 3.14156592; - curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout); - puts(buffer); - printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout); - } -#endif - - return 0; -} - -#endif diff --git a/Utilities/cmcurl/multi.c b/Utilities/cmcurl/multi.c deleted file mode 100644 index 869d568..0000000 --- a/Utilities/cmcurl/multi.c +++ /dev/null @@ -1,1988 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include - -#include "urldata.h" -#include "transfer.h" -#include "url.h" -#include "connect.h" -#include "progress.h" -#include "memory.h" -#include "easyif.h" -#include "multiif.h" -#include "sendf.h" -#include "timeval.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -struct Curl_message { - /* the 'CURLMsg' is the part that is visible to the external user */ - struct CURLMsg extmsg; - struct Curl_message *next; -}; - -typedef enum { - CURLM_STATE_INIT, /* start in this state */ - CURLM_STATE_CONNECT, /* resolve/connect has been sent off */ - CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */ - CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */ - CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect - phase */ - CURLM_STATE_WAITDO, /* wait for our turn to send the request */ - CURLM_STATE_DO, /* start send off the request (part 1) */ - CURLM_STATE_DOING, /* sending off the request (part 1) */ - CURLM_STATE_DO_MORE, /* send off the request (part 2) */ - CURLM_STATE_DO_DONE, /* done sending off request */ - CURLM_STATE_WAITPERFORM, /* wait for our turn to read the response */ - CURLM_STATE_PERFORM, /* transfer data */ - CURLM_STATE_TOOFAST, /* wait because limit-rate exceeded */ - CURLM_STATE_DONE, /* post data transfer operation */ - CURLM_STATE_COMPLETED, /* operation complete */ - CURLM_STATE_CANCELLED, /* cancelled */ - - CURLM_STATE_LAST /* not a true state, never use this */ -} CURLMstate; - -/* we support N sockets per easy handle. Set the corresponding bit to what - action we should wait for */ -#define MAX_SOCKSPEREASYHANDLE 5 -#define GETSOCK_READABLE (0x00ff) -#define GETSOCK_WRITABLE (0xff00) - -struct closure { - struct closure *next; /* a simple one-way list of structs */ - struct SessionHandle *easy_handle; -}; - -struct Curl_one_easy { - /* first, two fields for the linked list of these */ - struct Curl_one_easy *next; - struct Curl_one_easy *prev; - - struct SessionHandle *easy_handle; /* the easy handle for this unit */ - struct connectdata *easy_conn; /* the "unit's" connection */ - - CURLMstate state; /* the handle's state */ - CURLcode result; /* previous result */ - - struct Curl_message *msg; /* A pointer to one single posted message. - Cleanup should be done on this pointer NOT on - the linked list in Curl_multi. This message - will be deleted when this handle is removed - from the multi-handle */ - int msg_num; /* number of messages left in 'msg' to return */ - - /* Array with the plain socket numbers this handle takes care of, in no - particular order. Note that all sockets are added to the sockhash, where - the state etc are also kept. This array is mostly used to detect when a - socket is to be removed from the hash. See singlesocket(). */ - curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; - int numsocks; -}; - -#define CURL_MULTI_HANDLE 0x000bab1e - -#define GOOD_MULTI_HANDLE(x) \ - ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE)) -#define GOOD_EASY_HANDLE(x) \ - (((struct SessionHandle *)x)->magic == CURLEASY_MAGIC_NUMBER) - -/* 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. */ - long type; - - /* We have a linked list with easy handles */ - struct Curl_one_easy easy; - - int num_easy; /* amount of entries in the linked list above. */ - int num_msgs; /* amount of messages in the easy handles */ - int num_alive; /* amount of easy handles that are added but have not yet - reached COMPLETE state */ - - /* callback function and user data pointer for the *socket() API */ - curl_socket_callback socket_cb; - void *socket_userp; - - /* Hostname cache */ - struct curl_hash *hostcache; - - /* timetree points to the splay-tree of time nodes to figure out expire - times of all currently set timers */ - struct Curl_tree *timetree; - - /* '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; - - /* Whether pipelining is enabled for this multi handle */ - bool pipelining_enabled; - - /* shared connection cache */ - struct conncache *connc; - - /* list of easy handles kept around for doing nice connection closures */ - struct closure *closure; - - /* timer callback and user data pointer for the *socket() API */ - curl_multi_timer_callback timer_cb; - void *timer_userp; - time_t timer_lastcall; /* the fixed time for the timeout for the previous - callback */ -}; - -static bool multi_conn_using(struct Curl_multi *multi, - struct SessionHandle *data); -static void singlesocket(struct Curl_multi *multi, - struct Curl_one_easy *easy); -static void add_closure(struct Curl_multi *multi, - struct SessionHandle *data); -static int update_timer(struct Curl_multi *multi); - -#ifdef CURLDEBUG -static const char *statename[]={ - "INIT", - "CONNECT", - "WAITRESOLVE", - "WAITCONNECT", - "PROTOCONNECT", - "WAITDO", - "DO", - "DOING", - "DO_MORE", - "DO_DONE", - "WAITPERFORM", - "PERFORM", - "TOOFAST", - "DONE", - "COMPLETED", - "CANCELLED" -}; - -void curl_multi_dump(CURLM *multi_handle); -#endif - -/* always use this function to change state, to make debugging easier */ -static void multistate(struct Curl_one_easy *easy, CURLMstate state) -{ -#ifdef CURLDEBUG - long index = -1; -#endif - CURLMstate oldstate = easy->state; - - if(oldstate == state) - /* don't bother when the new state is the same as the old state */ - return; - - easy->state = state; - -#ifdef CURLDEBUG - if(easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) - index = easy->easy_conn->connectindex; - - infof(easy->easy_handle, - "STATE: %s => %s handle %p; (connection #%ld) \n", - statename[oldstate], statename[easy->state], - (char *)easy, index); -#endif - if(state == CURLM_STATE_COMPLETED) - /* changing to COMPLETED means there's one less easy handle 'alive' */ - easy->easy_handle->multi->num_alive--; -} - -/* - * We add one of these structs to the sockhash for a particular socket - */ - -struct Curl_sh_entry { - struct SessionHandle *easy; - time_t timestamp; - long inuse; - int action; /* what action READ/WRITE this socket waits for */ - curl_socket_t socket; /* mainly to ease debugging */ - void *socketp; /* settable by users with curl_multi_assign() */ -}; -/* bits for 'action' having no bits means this socket is not expecting any - action */ -#define SH_READ 1 -#define SH_WRITE 2 - -/* make sure this socket is present in the hash for this handle */ -static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, - curl_socket_t s, - struct SessionHandle *data) -{ - struct Curl_sh_entry *there = - Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); - struct Curl_sh_entry *check; - - if(there) - /* it is present, return fine */ - return there; - - /* not present, add it */ - check = calloc(sizeof(struct Curl_sh_entry), 1); - if(!check) - return NULL; /* major failure */ - check->easy = data; - check->socket = s; - - /* make/add new hash entry */ - if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { - free(check); - return NULL; /* major failure */ - } - - return check; /* things are good in sockhash land */ -} - - -/* delete the given socket + handle from the hash */ -static void sh_delentry(struct curl_hash *sh, curl_socket_t s) -{ - struct Curl_sh_entry *there = - Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); - - if(there) { - /* this socket is in the hash */ - /* We remove the hash entry. (This'll end up in a call to - sh_freeentry().) */ - Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); - } -} - -/* - * free a sockhash entry - */ -static void sh_freeentry(void *freethis) -{ - struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; - - free(p); -} - -/* - * sh_init() creates a new socket hash and returns the handle for it. - * - * Quote from README.multi_socket: - * - * "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. 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 struct curl_hash *sh_init(void) -{ - return Curl_hash_alloc(97, sh_freeentry); -} - -CURLM *curl_multi_init(void) -{ - struct Curl_multi *multi = (void *)calloc(sizeof(struct Curl_multi), 1); - - if(!multi) - return NULL; - - multi->type = CURL_MULTI_HANDLE; - - multi->hostcache = Curl_mk_dnscache(); - if(!multi->hostcache) { - /* failure, free mem and bail out */ - free(multi); - return NULL; - } - - multi->sockhash = sh_init(); - if(!multi->sockhash) { - /* failure, free mem and bail out */ - Curl_hash_destroy(multi->hostcache); - free(multi); - return NULL; - } - - multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1); - if(!multi->connc) { - Curl_hash_destroy(multi->hostcache); - free(multi); - return NULL; - } - - return (CURLM *) multi; -} - -CURLMcode curl_multi_add_handle(CURLM *multi_handle, - CURL *easy_handle) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - struct closure *cl; - struct closure *prev=NULL; - - /* 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(easy_handle)) - return CURLM_BAD_EASY_HANDLE; - - /* Prevent users to add the same handle more than once! */ - if(((struct SessionHandle *)easy_handle)->multi) - /* possibly we should create a new unique error code for this condition */ - return CURLM_BAD_EASY_HANDLE; - - /* Now, time to add an easy handle to the multi stack */ - easy = (struct Curl_one_easy *)calloc(sizeof(struct Curl_one_easy), 1); - if(!easy) - return CURLM_OUT_OF_MEMORY; - - cl = multi->closure; - while(cl) { - struct closure *next = cl->next; - if(cl->easy_handle == (struct SessionHandle *)easy_handle) { - /* remove this handle from the closure list */ - free(cl); - if(prev) - prev->next = next; - else - multi->closure = next; - break; /* no need to continue since this handle can only be present once - in the list */ - } - cl = next; - } - - /* set the easy handle */ - easy->easy_handle = easy_handle; - multistate(easy, CURLM_STATE_INIT); - - /* for multi interface connections, we share DNS cache automatically if the - easy handle's one is currently private. */ - if (easy->easy_handle->dns.hostcache && - (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) { - Curl_hash_destroy(easy->easy_handle->dns.hostcache); - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; - } - - if (!easy->easy_handle->dns.hostcache || - (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) { - easy->easy_handle->dns.hostcache = multi->hostcache; - easy->easy_handle->dns.hostcachetype = HCACHE_MULTI; - } - - if(easy->easy_handle->state.connc) { - if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) { - /* kill old private version */ - Curl_rm_connc(easy->easy_handle->state.connc); - /* point out our shared one instead */ - easy->easy_handle->state.connc = multi->connc; - } - /* else it is already using multi? */ - } - else - /* point out our shared one */ - easy->easy_handle->state.connc = multi->connc; - - /* Make sure the type is setup correctly */ - easy->easy_handle->state.connc->type = CONNCACHE_MULTI; - - /* We add this new entry first in the list. We make our 'next' point to the - previous next and our 'prev' point back to the 'first' struct */ - easy->next = multi->easy.next; - easy->prev = &multi->easy; - - /* make 'easy' the first node in the chain */ - multi->easy.next = easy; - - /* if there was a next node, make sure its 'prev' pointer links back to - the new node */ - if(easy->next) - easy->next->prev = easy; - - Curl_easy_addmulti(easy_handle, multi_handle); - - /* make the SessionHandle struct refer back to this struct */ - easy->easy_handle->set.one_easy = easy; - - /* increase the node-counter */ - multi->num_easy++; - - if((multi->num_easy * 4) > multi->connc->num) { - /* We want the connection cache to have plenty room. Before we supported - the shared cache every single easy handle had 5 entries in their cache - by default. */ - CURLcode res = Curl_ch_connc(easy_handle, multi->connc, - multi->connc->num*4); - if(res != CURLE_OK) - /* TODO: we need to do some cleaning up here! */ - return CURLM_OUT_OF_MEMORY; - } - - /* increase the alive-counter */ - multi->num_alive++; - - update_timer(multi); - return CURLM_OK; -} - -#if 0 -/* Debug-function, used like this: - * - * Curl_hash_print(multi->sockhash, debug_print_sock_hash); - * - * Enable the hash print function first by editing hash.c - */ -static void debug_print_sock_hash(void *p) -{ - struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; - - fprintf(stderr, " [easy %p/magic %x/socket %d]", - (void *)sh->easy, sh->easy->magic, sh->socket); -} -#endif - -CURLMcode curl_multi_remove_handle(CURLM *multi_handle, - CURL *curl_handle) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - - /* 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(curl_handle)) - return CURLM_BAD_EASY_HANDLE; - - /* scan through the list and remove the 'curl_handle' */ - easy = multi->easy.next; - while(easy) { - if(easy->easy_handle == (struct SessionHandle *)curl_handle) - break; - easy=easy->next; - } - - if(easy) { - bool premature = (bool)(easy->state != CURLM_STATE_COMPLETED); - - /* If the 'state' is not INIT or COMPLETED, we might need to do something - nice to put the easy_handle in a good known state when this returns. */ - if(premature) - /* this handle is "alive" so we need to count down the total number of - alive connections when this is removed */ - multi->num_alive--; - - if (easy->easy_handle->state.is_in_pipeline && - easy->state > CURLM_STATE_DO) { - /* If the handle is in a pipeline and has finished sending off its - request, we need to remember the fact that we want to remove this - handle but do the actual removal at a later time */ - easy->easy_handle->state.cancelled = TRUE; - return CURLM_OK; - } - - /* The timer must be shut down before easy->multi is set to NULL, - else the timenode will remain in the splay tree after - curl_easy_cleanup is called. */ - Curl_expire(easy->easy_handle, 0); - - if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { - /* clear out the usage of the shared DNS cache */ - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; - } - - /* if we have a connection we must call Curl_done() here so that we - don't leave a half-baked one around */ - if(easy->easy_conn) { - /* Set up the association right */ - easy->easy_conn->data = easy->easy_handle; - - /* Curl_done() clears the conn->data field to lose the association - between the easy handle and the connection */ - Curl_done(&easy->easy_conn, easy->result, premature); - - if(easy->easy_conn) - /* the connection is still alive, set back the association to enable - the check below to trigger TRUE */ - easy->easy_conn->data = easy->easy_handle; - } - - /* If this easy_handle was the last one in charge for one or more - connections a the shared connection cache, we might need to keep this - handle around until either A) the connection is closed and killed - properly, or B) another easy_handle uses the connection. - - The reason why we need to have a easy_handle associated with a live - connection is simply that some connections will need a handle to get - closed down properly. Currently, the only connections that need to keep - a easy_handle handle around are using FTP(S). Such connections have - the PROT_CLOSEACTION bit set. - - Thus, we need to check for all connections in the shared cache that - points to this handle and are using PROT_CLOSEACTION. If there's any, - we need to add this handle to the list of "easy handles kept around for - nice connection closures". - */ - if(multi_conn_using(multi, easy->easy_handle)) { - /* There's at least one connection using this handle so we must keep - this handle around. We also keep the connection cache pointer - pointing to the shared one since that will be used on close as - well. */ - easy->easy_handle->state.shared_conn = multi; - - /* this handle is still being used by a shared connection cache and - thus we leave it around for now */ - add_closure(multi, easy->easy_handle); - } - - if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) { - /* if this was using the shared connection cache we clear the pointer - to that since we're not part of that handle anymore */ - easy->easy_handle->state.connc = NULL; - - /* and modify the connectindex since this handle can't point to the - connection cache anymore */ - if(easy->easy_conn) - easy->easy_conn->connectindex = -1; - } - - /* change state without using multistate(), only to make singlesocket() do - what we want */ - easy->state = CURLM_STATE_COMPLETED; - singlesocket(multi, easy); /* to let the application know what sockets - that vanish with this handle */ - - Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association - to this multi handle */ - - /* make the previous node point to our next */ - if(easy->prev) - easy->prev->next = easy->next; - /* make our next point to our previous node */ - if(easy->next) - easy->next->prev = easy->prev; - - easy->easy_handle->set.one_easy = NULL; /* detached */ - - /* NOTE NOTE NOTE - We do not touch the easy handle here! */ - if (easy->msg) - free(easy->msg); - free(easy); - - multi->num_easy--; /* one less to care about now */ - - update_timer(multi); - return CURLM_OK; - } - else - return CURLM_BAD_EASY_HANDLE; /* twasn't found */ -} - -bool Curl_multi_canPipeline(struct Curl_multi* multi) -{ - return multi->pipelining_enabled; -} - -static int waitconnect_getsock(struct connectdata *conn, - curl_socket_t *sock, - int numsocks) -{ - if(!numsocks) - return GETSOCK_BLANK; - - sock[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); -} - -static int domore_getsock(struct connectdata *conn, - curl_socket_t *sock, - int numsocks) -{ - if(!numsocks) - return GETSOCK_BLANK; - - /* When in DO_MORE state, we could be either waiting for us - to connect to a remote site, or we could wait for that site - to connect to us. It makes a difference in the way: if we - connect to the site we wait for the socket to become writable, if - the site connects to us we wait for it to become readable */ - sock[0] = conn->sock[SECONDARYSOCKET]; - - return GETSOCK_WRITESOCK(0); -} - -/* returns bitmapped flags for this handle and its sockets */ -static int multi_getsock(struct Curl_one_easy *easy, - curl_socket_t *socks, /* points to numsocks number - of sockets */ - int numsocks) -{ - if (easy->easy_handle->state.pipe_broke) { - return 0; - } - - if (easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) { - /* Set up ownership correctly */ - easy->easy_conn->data = easy->easy_handle; - } - - switch(easy->state) { - case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */ - default: - /* this will get called with CURLM_STATE_COMPLETED when a handle is - removed */ - return 0; - - case CURLM_STATE_WAITRESOLVE: - return Curl_resolv_getsock(easy->easy_conn, socks, numsocks); - - case CURLM_STATE_PROTOCONNECT: - return Curl_protocol_getsock(easy->easy_conn, socks, numsocks); - - case CURLM_STATE_DOING: - return Curl_doing_getsock(easy->easy_conn, socks, numsocks); - - case CURLM_STATE_WAITCONNECT: - return waitconnect_getsock(easy->easy_conn, socks, numsocks); - - case CURLM_STATE_DO_MORE: - return domore_getsock(easy->easy_conn, socks, numsocks); - - case CURLM_STATE_PERFORM: - case CURLM_STATE_WAITPERFORM: - return Curl_single_getsock(easy->easy_conn, socks, numsocks); - } - -} - -CURLMcode curl_multi_fdset(CURLM *multi_handle, - fd_set *read_fd_set, fd_set *write_fd_set, - fd_set *exc_fd_set, int *max_fd) -{ - /* 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_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - int this_max_fd=-1; - curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; - int bitmap; - int i; - (void)exc_fd_set; /* not used */ - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - easy=multi->easy.next; - while(easy) { - bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); - - for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { - curl_socket_t s = CURL_SOCKET_BAD; - - if(bitmap & GETSOCK_READSOCK(i)) { - FD_SET(sockbunch[i], read_fd_set); - s = sockbunch[i]; - } - if(bitmap & GETSOCK_WRITESOCK(i)) { - FD_SET(sockbunch[i], write_fd_set); - s = sockbunch[i]; - } - if(s == CURL_SOCKET_BAD) - /* this socket is unused, break out of loop */ - break; - else { - if((int)s > this_max_fd) - this_max_fd = (int)s; - } - } - - easy = easy->next; /* check next handle */ - } - - *max_fd = this_max_fd; - - return CURLM_OK; -} - -static CURLMcode multi_runsingle(struct Curl_multi *multi, - struct Curl_one_easy *easy) -{ - struct Curl_message *msg = NULL; - bool connected; - bool async; - bool protocol_connect = 0; - bool dophase_done; - bool done; - CURLMcode result = CURLM_OK; - struct Curl_transfer_keeper *k; - - do { - - if(!GOOD_EASY_HANDLE(easy->easy_handle)) - return CURLM_BAD_EASY_HANDLE; - - if (easy->easy_handle->state.pipe_broke) { - infof(easy->easy_handle, "Pipe broke: handle 0x%x, url = %s\n", - easy, easy->easy_handle->reqdata.path); - if(easy->easy_handle->state.is_in_pipeline) { - /* Head back to the CONNECT state */ - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - easy->result = CURLE_OK; - } else { - easy->result = CURLE_COULDNT_CONNECT; - multistate(easy, CURLM_STATE_COMPLETED); - } - - easy->easy_handle->state.pipe_broke = FALSE; - easy->easy_conn = NULL; - break; - } - - if (easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) { - /* Make sure we set the connection's current owner */ - easy->easy_conn->data = easy->easy_handle; - } - - if (CURLM_STATE_WAITCONNECT <= easy->state && - easy->state <= CURLM_STATE_DO && - easy->easy_handle->change.url_changed) { - char *gotourl; - Curl_posttransfer(easy->easy_handle); - - easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); - /* We make sure that the pipe broken flag is reset - because in this case, it isn't an actual break */ - easy->easy_handle->state.pipe_broke = FALSE; - if(CURLE_OK == easy->result) { - gotourl = strdup(easy->easy_handle->change.url); - if(gotourl) { - easy->easy_handle->change.url_changed = FALSE; - easy->result = Curl_follow(easy->easy_handle, gotourl, FALSE); - if(CURLE_OK == easy->result) - multistate(easy, CURLM_STATE_CONNECT); - else - free(gotourl); - } - else { - easy->result = CURLE_OUT_OF_MEMORY; - multistate(easy, CURLM_STATE_COMPLETED); - break; - } - } - } - - easy->easy_handle->change.url_changed = FALSE; - - switch(easy->state) { - case CURLM_STATE_INIT: - /* init this transfer. */ - easy->result=Curl_pretransfer(easy->easy_handle); - - if(CURLE_OK == easy->result) { - /* after init, go CONNECT */ - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - - easy->easy_handle->state.used_interface = Curl_if_multi; - } - break; - - case CURLM_STATE_CONNECT: - /* Connect. We get a connection identifier filled in. */ - Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE); - easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn, - &async, &protocol_connect); - - if(CURLE_OK == easy->result) { - /* Add this handle to the send pipeline */ - Curl_addHandleToPipeline(easy->easy_handle, - easy->easy_conn->send_pipe); - - if(async) - /* We're now waiting for an asynchronous name lookup */ - multistate(easy, CURLM_STATE_WAITRESOLVE); - else { - /* after the connect has been sent off, go WAITCONNECT unless the - protocol connect is already done and we can go directly to - WAITDO! */ - result = CURLM_CALL_MULTI_PERFORM; - - if(protocol_connect) { - multistate(easy, CURLM_STATE_WAITDO); - } else { - multistate(easy, CURLM_STATE_WAITCONNECT); - } - } - } - break; - - case CURLM_STATE_WAITRESOLVE: - /* awaiting an asynch name resolve to complete */ - { - struct Curl_dns_entry *dns = NULL; - - /* check if we have the name resolved by now */ - easy->result = Curl_is_resolved(easy->easy_conn, &dns); - - if(dns) { - /* Perform the next step in the connection phase, and then move on - to the WAITCONNECT state */ - easy->result = Curl_async_resolved(easy->easy_conn, - &protocol_connect); - - if(CURLE_OK != easy->result) - /* if Curl_async_resolved() returns failure, the connection struct - is already freed and gone */ - easy->easy_conn = NULL; /* no more connection */ - else { - /* call again please so that we get the next socket setup */ - result = CURLM_CALL_MULTI_PERFORM; - if(protocol_connect) - multistate(easy, CURLM_STATE_DO); - else - multistate(easy, CURLM_STATE_WAITCONNECT); - } - } - - if(CURLE_OK != easy->result) { - /* failure detected */ - Curl_disconnect(easy->easy_conn); /* disconnect properly */ - easy->easy_conn = NULL; /* no more connection */ - break; - } - } - break; - - case CURLM_STATE_WAITCONNECT: - /* awaiting a completion of an asynch connect */ - easy->result = Curl_is_connected(easy->easy_conn, - FIRSTSOCKET, - &connected); - if(connected) - easy->result = Curl_protocol_connect(easy->easy_conn, - &protocol_connect); - - if(CURLE_OK != easy->result) { - /* failure detected */ - Curl_disconnect(easy->easy_conn); /* close the connection */ - easy->easy_conn = NULL; /* no more connection */ - break; - } - - if(connected) { - if(!protocol_connect) { - /* We have a TCP connection, but 'protocol_connect' may be false - and then we continue to 'STATE_PROTOCONNECT'. If protocol - connect is TRUE, we move on to STATE_DO. */ - multistate(easy, CURLM_STATE_PROTOCONNECT); - } - else { - /* after the connect has completed, go WAITDO */ - multistate(easy, CURLM_STATE_WAITDO); - - result = CURLM_CALL_MULTI_PERFORM; - } - } - break; - - case CURLM_STATE_PROTOCONNECT: - /* protocol-specific connect phase */ - easy->result = Curl_protocol_connecting(easy->easy_conn, - &protocol_connect); - if(protocol_connect) { - /* after the connect has completed, go WAITDO */ - multistate(easy, CURLM_STATE_WAITDO); - result = CURLM_CALL_MULTI_PERFORM; - } - else if(easy->result) { - /* failure detected */ - Curl_posttransfer(easy->easy_handle); - Curl_done(&easy->easy_conn, easy->result, FALSE); - Curl_disconnect(easy->easy_conn); /* close the connection */ - easy->easy_conn = NULL; /* no more connection */ - } - break; - - case CURLM_STATE_WAITDO: - /* Wait for our turn to DO when we're pipelining requests */ -#ifdef CURLDEBUG - infof(easy->easy_handle, "Conn %d send pipe %d inuse %d athead %d\n", - easy->easy_conn->connectindex, - easy->easy_conn->send_pipe->size, - easy->easy_conn->writechannel_inuse, - Curl_isHandleAtHead(easy->easy_handle, - easy->easy_conn->send_pipe)); -#endif - if (!easy->easy_conn->writechannel_inuse && - Curl_isHandleAtHead(easy->easy_handle, - easy->easy_conn->send_pipe)) { - /* Grab the channel */ - easy->easy_conn->writechannel_inuse = TRUE; - multistate(easy, CURLM_STATE_DO); - result = CURLM_CALL_MULTI_PERFORM; - } - break; - - case CURLM_STATE_DO: - if(easy->easy_handle->set.connect_only) { - /* keep connection open for application to use the socket */ - easy->easy_conn->bits.close = FALSE; - multistate(easy, CURLM_STATE_DONE); - easy->result = CURLE_OK; - result = CURLM_OK; - } - else { - /* Perform the protocol's DO action */ - easy->result = Curl_do(&easy->easy_conn, - &dophase_done); - - if(CURLE_OK == easy->result) { - - if(!dophase_done) { - /* DO was not completed in one function call, we must continue - DOING... */ - multistate(easy, CURLM_STATE_DOING); - result = CURLM_OK; - } - - /* after DO, go DO_DONE... or DO_MORE */ - else if(easy->easy_conn->bits.do_more) { - /* we're supposed to do more, but we need to sit down, relax - and wait a little while first */ - multistate(easy, CURLM_STATE_DO_MORE); - result = CURLM_OK; - } - else { - /* we're done with the DO, now DO_DONE */ - easy->result = Curl_readwrite_init(easy->easy_conn); - if(CURLE_OK == easy->result) { - multistate(easy, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; - } - } - } - else { - /* failure detected */ - Curl_posttransfer(easy->easy_handle); - Curl_done(&easy->easy_conn, easy->result, FALSE); - Curl_disconnect(easy->easy_conn); /* close the connection */ - easy->easy_conn = NULL; /* no more connection */ - } - } - break; - - case CURLM_STATE_DOING: - /* we continue DOING until the DO phase is complete */ - easy->result = Curl_protocol_doing(easy->easy_conn, - &dophase_done); - if(CURLE_OK == easy->result) { - if(dophase_done) { - /* after DO, go PERFORM... or DO_MORE */ - if(easy->easy_conn->bits.do_more) { - /* we're supposed to do more, but we need to sit down, relax - and wait a little while first */ - multistate(easy, CURLM_STATE_DO_MORE); - result = CURLM_OK; - } - else { - /* we're done with the DO, now DO_DONE */ - easy->result = Curl_readwrite_init(easy->easy_conn); - if(CURLE_OK == easy->result) { - multistate(easy, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; - } - } - } /* dophase_done */ - } - else { - /* failure detected */ - Curl_posttransfer(easy->easy_handle); - Curl_done(&easy->easy_conn, easy->result, FALSE); - Curl_disconnect(easy->easy_conn); /* close the connection */ - easy->easy_conn = NULL; /* no more connection */ - } - break; - - case CURLM_STATE_DO_MORE: - /* Ready to do more? */ - easy->result = Curl_is_connected(easy->easy_conn, - SECONDARYSOCKET, - &connected); - if(connected) { - /* - * When we are connected, DO MORE and then go DO_DONE - */ - easy->result = Curl_do_more(easy->easy_conn); - - if(CURLE_OK == easy->result) - easy->result = Curl_readwrite_init(easy->easy_conn); - else - /* Remove ourselves from the send pipeline */ - Curl_removeHandleFromPipeline(easy->easy_handle, - easy->easy_conn->send_pipe); - - if(CURLE_OK == easy->result) { - multistate(easy, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; - } - } - break; - - case CURLM_STATE_DO_DONE: - /* Remove ourselves from the send pipeline */ - Curl_removeHandleFromPipeline(easy->easy_handle, - easy->easy_conn->send_pipe); - /* Add ourselves to the recv pipeline */ - Curl_addHandleToPipeline(easy->easy_handle, - easy->easy_conn->recv_pipe); - multistate(easy, CURLM_STATE_WAITPERFORM); - result = CURLM_CALL_MULTI_PERFORM; - break; - - case CURLM_STATE_WAITPERFORM: -#ifdef CURLDEBUG - infof(easy->easy_handle, "Conn %d recv pipe %d inuse %d athead %d\n", - easy->easy_conn->connectindex, - easy->easy_conn->recv_pipe->size, - easy->easy_conn->readchannel_inuse, - Curl_isHandleAtHead(easy->easy_handle, - easy->easy_conn->recv_pipe)); -#endif - /* Wait for our turn to PERFORM */ - if (!easy->easy_conn->readchannel_inuse && - Curl_isHandleAtHead(easy->easy_handle, - easy->easy_conn->recv_pipe)) { - /* Grab the channel */ - easy->easy_conn->readchannel_inuse = TRUE; - multistate(easy, CURLM_STATE_PERFORM); - result = CURLM_CALL_MULTI_PERFORM; - } - break; - - case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ - /* if both rates are within spec, resume transfer */ - Curl_pgrsUpdate(easy->easy_conn); - if ( ( ( easy->easy_handle->set.max_send_speed == 0 ) || - ( easy->easy_handle->progress.ulspeed < - easy->easy_handle->set.max_send_speed ) ) && - ( ( easy->easy_handle->set.max_recv_speed == 0 ) || - ( easy->easy_handle->progress.dlspeed < - easy->easy_handle->set.max_recv_speed ) ) - ) - multistate(easy, CURLM_STATE_PERFORM); - break; - - case CURLM_STATE_PERFORM: - /* check if over speed */ - if ( ( ( easy->easy_handle->set.max_send_speed > 0 ) && - ( easy->easy_handle->progress.ulspeed > - easy->easy_handle->set.max_send_speed ) ) || - ( ( easy->easy_handle->set.max_recv_speed > 0 ) && - ( easy->easy_handle->progress.dlspeed > - easy->easy_handle->set.max_recv_speed ) ) - ) { - /* Transfer is over the speed limit. Change state. TODO: Call - * Curl_expire() with the time left until we're targeted to be below - * the speed limit again. */ - multistate(easy, CURLM_STATE_TOOFAST ); - break; - } - - /* read/write data if it is ready to do so */ - easy->result = Curl_readwrite(easy->easy_conn, &done); - - k = &easy->easy_handle->reqdata.keep; - - if (!(k->keepon & KEEP_READ)) { - /* We're done reading */ - easy->easy_conn->readchannel_inuse = FALSE; - } - - if (!(k->keepon & KEEP_WRITE)) { - /* We're done writing */ - easy->easy_conn->writechannel_inuse = FALSE; - } - - if(easy->result) { - /* The transfer phase returned error, we mark the connection to get - * closed to prevent being re-used. This is becasue we can't - * possibly know if the connection is in a good shape or not now. */ - easy->easy_conn->bits.close = TRUE; - - if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) { - /* if we failed anywhere, we must clean up the secondary socket if - it was used */ - sclose(easy->easy_conn->sock[SECONDARYSOCKET]); - easy->easy_conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } - Curl_posttransfer(easy->easy_handle); - Curl_done(&easy->easy_conn, easy->result, FALSE); - } - else if(TRUE == done) { - char *newurl; - bool retry = Curl_retry_request(easy->easy_conn, &newurl); - - /* call this even if the readwrite function returned error */ - Curl_posttransfer(easy->easy_handle); - - /* When we follow redirects, must to go back to the CONNECT state */ - if(easy->easy_handle->reqdata.newurl || retry) { - Curl_removeHandleFromPipeline(easy->easy_handle, - easy->easy_conn->recv_pipe); - if(!retry) { - /* if the URL is a follow-location and not just a retried request - then figure out the URL here */ - newurl = easy->easy_handle->reqdata.newurl; - easy->easy_handle->reqdata.newurl = NULL; - } - easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); - if(easy->result == CURLE_OK) - easy->result = Curl_follow(easy->easy_handle, newurl, retry); - if(CURLE_OK == easy->result) { - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - } - else - /* Since we "took it", we are in charge of freeing this on - failure */ - free(newurl); - } - else { - /* after the transfer is done, go DONE */ - multistate(easy, CURLM_STATE_DONE); - result = CURLM_CALL_MULTI_PERFORM; - } - } - - break; - - case CURLM_STATE_DONE: - /* Remove ourselves from the receive pipeline */ - Curl_removeHandleFromPipeline(easy->easy_handle, - easy->easy_conn->recv_pipe); - easy->easy_handle->state.is_in_pipeline = FALSE; - - if (easy->easy_conn->bits.stream_was_rewound) { - /* This request read past its response boundary so we quickly - let the other requests consume those bytes since there is no - guarantee that the socket will become active again */ - result = CURLM_CALL_MULTI_PERFORM; - } - - if (!easy->easy_handle->state.cancelled) { - /* post-transfer command */ - easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); - - /* after we have DONE what we're supposed to do, go COMPLETED, and - it doesn't matter what the Curl_done() returned! */ - multistate(easy, CURLM_STATE_COMPLETED); - } - - break; - - case CURLM_STATE_COMPLETED: - if (easy->easy_handle->state.cancelled) - /* Go into the CANCELLED state if we were cancelled */ - multistate(easy, CURLM_STATE_CANCELLED); - - /* this is a completed transfer, it is likely to still be connected */ - - /* This node should be delinked from the list now and we should post - an information message that we are complete. */ - break; - - case CURLM_STATE_CANCELLED: - /* Cancelled transfer, wait to be cleaned up */ - break; - - default: - return CURLM_INTERNAL_ERROR; - } - - if(CURLM_STATE_COMPLETED != easy->state) { - if(CURLE_OK != easy->result) { - /* - * If an error was returned, and we aren't in completed state now, - * then we go to completed and consider this transfer aborted. - */ - easy->easy_handle->state.is_in_pipeline = FALSE; - easy->easy_handle->state.pipe_broke = FALSE; - - if(easy->easy_conn) { - /* if this has a connection, unsubscribe from the pipelines */ - easy->easy_conn->writechannel_inuse = FALSE; - easy->easy_conn->readchannel_inuse = FALSE; - } - multistate(easy, CURLM_STATE_COMPLETED); - } - } - - } while (easy->easy_handle->change.url_changed); - - if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) { - if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { - /* clear out the usage of the shared DNS cache */ - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; - } - - /* now add a node to the Curl_message linked list with this info */ - msg = (struct Curl_message *)malloc(sizeof(struct Curl_message)); - - if(!msg) - return CURLM_OUT_OF_MEMORY; - - msg->extmsg.msg = CURLMSG_DONE; - msg->extmsg.easy_handle = easy->easy_handle; - msg->extmsg.data.result = easy->result; - msg->next = NULL; - - easy->msg = msg; - easy->msg_num = 1; /* there is one unread message here */ - - multi->num_msgs++; /* increase message counter */ - } - - return result; -} - - -CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - CURLMcode returncode=CURLM_OK; - struct Curl_tree *t; - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - easy=multi->easy.next; - while(easy) { - CURLMcode result; - - if (easy->easy_handle->state.cancelled && - easy->state == CURLM_STATE_CANCELLED) { - /* Remove cancelled handles once it's safe to do so */ - Curl_multi_rmeasy(multi_handle, easy->easy_handle); - easy->easy_handle = NULL; - easy = easy->next; - continue; - } - - result = multi_runsingle(multi, easy); - if(result) - returncode = result; - - easy = easy->next; /* operate on next handle */ - } - - /* - * Simply remove all expired timers from the splay since handles are dealt - * with unconditionally by this function and curl_multi_timeout() requires - * that already passed/handled expire times are removed from the splay. - */ - do { - struct timeval now = Curl_tvnow(); - int key = now.tv_sec; /* drop the usec part */ - - multi->timetree = Curl_splaygetbest(key, multi->timetree, &t); - if (t) { - struct SessionHandle *d = t->payload; - struct timeval* tv = &d->state.expiretime; - - /* clear the expire times within the handles that we remove from the - splay tree */ - tv->tv_sec = 0; - tv->tv_usec = 0; - } - - } while(t); - - *running_handles = multi->num_alive; - - if ( CURLM_OK == returncode ) - update_timer(multi); - return returncode; -} - -/* This is called when an easy handle is cleanup'ed that is part of a multi - handle */ -void Curl_multi_rmeasy(void *multi_handle, CURL *easy_handle) -{ - curl_multi_remove_handle(multi_handle, easy_handle); -} - - -CURLMcode curl_multi_cleanup(CURLM *multi_handle) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - struct Curl_one_easy *nexteasy; - int i; - struct closure *cl; - struct closure *n; - - if(GOOD_MULTI_HANDLE(multi)) { - multi->type = 0; /* not good anymore */ - Curl_hash_destroy(multi->hostcache); - Curl_hash_destroy(multi->sockhash); - - /* go over all connections that have close actions */ - for(i=0; i< multi->connc->num; i++) { - if(multi->connc->connects[i] && - multi->connc->connects[i]->protocol & PROT_CLOSEACTION) { - Curl_disconnect(multi->connc->connects[i]); - multi->connc->connects[i] = NULL; - } - } - /* now walk through the list of handles we kept around only to be - able to close connections "properly" */ - cl = multi->closure; - while(cl) { - cl->easy_handle->state.shared_conn = NULL; /* no more shared */ - if(cl->easy_handle->state.closed) - /* close handle only if curl_easy_cleanup() already has been called - for this easy handle */ - Curl_close(cl->easy_handle); - n = cl->next; - free(cl); - cl= n; - } - - Curl_rm_connc(multi->connc); - - /* remove all easy handles */ - easy = multi->easy.next; - while(easy) { - nexteasy=easy->next; - if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { - /* clear out the usage of the shared DNS cache */ - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; - } - - /* Clear the pointer to the connection cache */ - easy->easy_handle->state.connc = NULL; - - Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */ - - if (easy->msg) - free(easy->msg); - free(easy); - easy = nexteasy; - } - - free(multi); - - return CURLM_OK; - } - else - return CURLM_BAD_HANDLE; -} - -CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - - *msgs_in_queue = 0; /* default to none */ - - if(GOOD_MULTI_HANDLE(multi)) { - struct Curl_one_easy *easy; - - if(!multi->num_msgs) - return NULL; /* no messages left to return */ - - easy=multi->easy.next; - while(easy) { - if(easy->msg_num) { - easy->msg_num--; - break; - } - easy = easy->next; - } - if(!easy) - return NULL; /* this means internal count confusion really */ - - multi->num_msgs--; - *msgs_in_queue = multi->num_msgs; - - return &easy->msg->extmsg; - } - else - return NULL; -} - -/* - * singlesocket() checks what sockets we deal with and their "action state" - * and if we have a different state in any of those sockets from last time we - * call the callback accordingly. - */ -static void singlesocket(struct Curl_multi *multi, - struct Curl_one_easy *easy) -{ - curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; - int i; - struct Curl_sh_entry *entry; - curl_socket_t s; - int num; - unsigned int curraction; - - memset(&socks, 0, sizeof(socks)); - for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) - socks[i] = CURL_SOCKET_BAD; - - /* Fill in the 'current' struct with the state as it is now: what sockets to - supervise and for what actions */ - curraction = multi_getsock(easy, socks, MAX_SOCKSPEREASYHANDLE); - - /* 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< MAX_SOCKSPEREASYHANDLE) && - (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))); - i++) { - int action = CURL_POLL_NONE; - - s = socks[i]; - - /* get it from the hash */ - entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); - - if(curraction & GETSOCK_READSOCK(i)) - action |= CURL_POLL_IN; - if(curraction & GETSOCK_WRITESOCK(i)) - action |= CURL_POLL_OUT; - - if(entry) { - /* yeps, already present so check if it has the same action set */ - if(entry->action == action) - /* same, continue */ - continue; - } - else { - /* this is a socket we didn't have before, add it! */ - entry = sh_addentry(multi->sockhash, s, easy->easy_handle); - if(!entry) - /* fatal */ - return; - } - - multi->socket_cb(easy->easy_handle, - s, - action, - multi->socket_userp, - entry ? entry->socketp : NULL); - - entry->action = action; /* store the current action state */ - } - - num = i; /* number of sockets */ - - /* when we've walked over all the sockets we should have right now, we must - make sure to detect sockets that are removed */ - for(i=0; i< easy->numsocks; i++) { - int j; - s = easy->sockets[i]; - for(j=0; jsockhash, (char *)&s, sizeof(s)); - if(entry) { - /* just a precaution, this socket really SHOULD be in the hash already - but in case it isn't, we don't have to tell the app to remove it - either since it never got to know about it */ - multi->socket_cb(easy->easy_handle, - s, - CURL_POLL_REMOVE, - multi->socket_userp, - entry ? entry->socketp : NULL); - - sh_delentry(multi->sockhash, s); - } - } - } - - memcpy(easy->sockets, socks, num*sizeof(curl_socket_t)); - easy->numsocks = num; -} - -static CURLMcode multi_socket(struct Curl_multi *multi, - bool checkall, - curl_socket_t s, - int *running_handles) -{ - CURLMcode result = CURLM_OK; - struct SessionHandle *data = NULL; - struct Curl_tree *t; - - if(checkall) { - struct Curl_one_easy *easyp; - /* *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 */ - easyp=multi->easy.next; - while(easyp) { - singlesocket(multi, easyp); - easyp = easyp->next; - } - - /* or should we fall-through and do the timer-based stuff? */ - return result; - } - else if (s != CURL_SOCKET_TIMEOUT) { - - struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); - - if(!entry) - /* unmatched socket, major problemo! */ - return CURLM_BAD_SOCKET; /* better return code? */ - - data = entry->easy; - - if(data->magic != CURLEASY_MAGIC_NUMBER) - /* bad bad bad bad bad bad bad */ - return CURLM_INTERNAL_ERROR; - - result = multi_runsingle(multi, data->set.one_easy); - - if(result == CURLM_OK) - /* get the socket(s) and check if the state has been changed since - last */ - singlesocket(multi, data->set.one_easy); - - /* 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 */ - } - - /* - * 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 { - int key; - struct timeval now; - - /* the first loop lap 'data' can be NULL */ - if(data) { - result = multi_runsingle(multi, data->set.one_easy); - - if(result == CURLM_OK) - /* get the socket(s) and check if the state has been changed since - last */ - singlesocket(multi, data->set.one_easy); - } - - /* Check if there's one (more) expired timer to deal with! This function - extracts a matching node if there is one */ - - now = Curl_tvnow(); - key = now.tv_sec; /* drop the usec part */ - - multi->timetree = Curl_splaygetbest(key, multi->timetree, &t); - if(t) { - /* assign 'data' to be the easy handle we just removed from the splay - tree */ - data = t->payload; - /* clear the expire time within the handle we removed from the - splay tree */ - data->state.expiretime.tv_sec = 0; - data->state.expiretime.tv_usec = 0; - } - - } while(t); - - *running_handles = multi->num_alive; - return result; -} - -CURLMcode curl_multi_setopt(CURLM *multi_handle, - CURLMoption option, ...) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - CURLMcode res = CURLM_OK; - va_list param; - - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - va_start(param, option); - - switch(option) { - case CURLMOPT_SOCKETFUNCTION: - multi->socket_cb = va_arg(param, curl_socket_callback); - break; - case CURLMOPT_SOCKETDATA: - multi->socket_userp = va_arg(param, void *); - break; - case CURLMOPT_PIPELINING: - multi->pipelining_enabled = (bool)(0 != va_arg(param, long)); - break; - case CURLMOPT_TIMERFUNCTION: - multi->timer_cb = va_arg(param, curl_multi_timer_callback); - break; - case CURLMOPT_TIMERDATA: - multi->timer_userp = va_arg(param, void *); - break; - default: - res = CURLM_UNKNOWN_OPTION; - break; - } - va_end(param); - return res; -} - - -CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, - int *running_handles) -{ - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, - running_handles); - if (CURLM_OK == result) - update_timer((struct Curl_multi *)multi_handle); - return result; -} - -CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) - -{ - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, - TRUE, CURL_SOCKET_BAD, running_handles); - if (CURLM_OK == result) - update_timer((struct Curl_multi *)multi_handle); - return result; -} - -static CURLMcode multi_timeout(struct Curl_multi *multi, - long *timeout_ms) -{ - if(multi->timetree) { - /* we have a tree of expire times */ - struct timeval now = Curl_tvnow(); - - /* splay the lowest to the bottom */ - multi->timetree = Curl_splay(0, multi->timetree); - - /* At least currently, the splay key is a time_t for the expire time */ - *timeout_ms = (multi->timetree->key - now.tv_sec) * 1000 - - now.tv_usec/1000; - if(*timeout_ms < 0) - /* 0 means immediately */ - *timeout_ms = 0; - } - else - *timeout_ms = -1; - - return CURLM_OK; -} - -CURLMcode curl_multi_timeout(CURLM *multi_handle, - long *timeout_ms) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - - /* First, make some basic checks that the CURLM handle is a good handle */ - if(!GOOD_MULTI_HANDLE(multi)) - return CURLM_BAD_HANDLE; - - return multi_timeout(multi, timeout_ms); -} - -/* - * Tell the application it should update its timers, if it subscribes to the - * update timer callback. - */ -static int update_timer(struct Curl_multi *multi) -{ - long timeout_ms; - if (!multi->timer_cb) - return 0; - if ( multi_timeout(multi, &timeout_ms) != CURLM_OK ) - return -1; - if ( timeout_ms < 0 ) - return 0; - - /* 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(multi->timetree->key == multi->timer_lastcall) - return 0; - - multi->timer_lastcall = multi->timetree->key; - - return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); -} - -/* given a number of milliseconds from now to use to set the 'act before - this'-time for the transfer, to be extracted by curl_multi_timeout() */ -void Curl_expire(struct SessionHandle *data, long milli) -{ - struct Curl_multi *multi = data->multi; - struct timeval *nowp = &data->state.expiretime; - int rc; - - /* this is only interesting for multi-interface using libcurl, and only - while there is still a multi interface struct remaining! */ - if(!multi) - return; - - if(!milli) { - /* No timeout, clear the time data. */ - if(nowp->tv_sec) { - /* Since this is an cleared time, we must remove the previous entry from - the splay tree */ - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error clearing splay node = %d\n", rc); - infof(data, "Expire cleared\n"); - nowp->tv_sec = 0; - nowp->tv_usec = 0; - } - } - else { - struct timeval set; - int rest; - - set = Curl_tvnow(); - set.tv_sec += milli/1000; - set.tv_usec += (milli%1000)*1000; - - rest = (int)(set.tv_usec - 1000000); - if(rest > 0) { - /* bigger than a full microsec */ - set.tv_sec++; - set.tv_usec -= 1000000; - } - - if(nowp->tv_sec) { - /* 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. */ - long diff = curlx_tvdiff(set, *nowp); - if(diff > 0) - /* the new expire time was later so we don't change this */ - return; - - /* Since this is an updated time, we must remove the previous entry from - the splay tree first and then re-add the new value */ - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error removing splay node = %d\n", rc); - } - - *nowp = set; -#if 0 - infof(data, "Expire at %ld / %ld (%ldms)\n", - (long)nowp->tv_sec, (long)nowp->tv_usec, milli); -#endif - data->state.timenode.payload = data; - multi->timetree = Curl_splayinsert((int)nowp->tv_sec, - multi->timetree, - &data->state.timenode); - } -#if 0 - Curl_splayprint(multi->timetree, 0, TRUE); -#endif -} - -CURLMcode curl_multi_assign(CURLM *multi_handle, - curl_socket_t s, void *hashp) -{ - struct Curl_sh_entry *there = NULL; - struct Curl_multi *multi = (struct Curl_multi *)multi_handle; - - if(s != CURL_SOCKET_BAD) - there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t)); - - if(!there) - return CURLM_BAD_SOCKET; - - there->socketp = hashp; - - return CURLM_OK; -} - -static bool multi_conn_using(struct Curl_multi *multi, - struct SessionHandle *data) -{ - /* any live CLOSEACTION-connections pointing to the give 'data' ? */ - int i; - - for(i=0; i< multi->connc->num; i++) { - if(multi->connc->connects[i] && - (multi->connc->connects[i]->data == data) && - multi->connc->connects[i]->protocol & PROT_CLOSEACTION) - return TRUE; - } - - return FALSE; -} - -/* Add the given data pointer to the list of 'closure handles' that are kept - around only to be able to close some connections nicely - just make sure - that this handle isn't already added, like for the cases when an easy - handle is removed, added and removed again... */ -static void add_closure(struct Curl_multi *multi, - struct SessionHandle *data) -{ - int i; - struct closure *cl = (struct closure *)calloc(sizeof(struct closure), 1); - struct closure *p=NULL; - struct closure *n; - if(cl) { - cl->easy_handle = data; - cl->next = multi->closure; - multi->closure = cl; - } - - p = multi->closure; - cl = p->next; /* start immediately on the second since the first is the one - we just added and it is _very_ likely to actually exist - used in the cache since that's the whole purpose of adding - it to this list! */ - - /* When adding, scan through all the other currently kept handles and see if - there are any connections still referring to them and kill them if not. */ - while(cl) { - bool inuse = FALSE; - for(i=0; i< multi->connc->num; i++) { - if(multi->connc->connects[i] && - (multi->connc->connects[i]->data == cl->easy_handle)) { - inuse = TRUE; - break; - } - } - - n = cl->next; - - if(!inuse) { - /* cl->easy_handle is now killable */ - infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle); - /* unmark it as not having a connection around that uses it anymore */ - cl->easy_handle->state.shared_conn= NULL; - Curl_close(cl->easy_handle); - if(p) - p->next = n; - else - multi->closure = n; - free(cl); - } - else - p = cl; - - cl = n; - } - -} - -#ifdef CURLDEBUG -void curl_multi_dump(CURLM *multi_handle) -{ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - int i; - fprintf(stderr, "* Multi status: %d handles, %d alive\n", - multi->num_easy, multi->num_alive); - for(easy=multi->easy.next; easy; easy = easy->next) { - if(easy->state != CURLM_STATE_COMPLETED) { - /* only display handles that are not completed */ - fprintf(stderr, "handle %p, state %s, %d sockets\n", - (void *)easy->easy_handle, - statename[easy->state], easy->numsocks); - for(i=0; i < easy->numsocks; i++) { - curl_socket_t s = easy->sockets[i]; - struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); - - fprintf(stderr, "%d ", (int)s); - if(!entry) { - fprintf(stderr, "INTERNAL CONFUSION\n"); - continue; - } - fprintf(stderr, "[%s %s] ", - entry->action&CURL_POLL_IN?"RECVING":"", - entry->action&CURL_POLL_OUT?"SENDING":""); - } - if(easy->numsocks) - fprintf(stderr, "\n"); - } - } -} -#endif diff --git a/Utilities/cmcurl/multiif.h b/Utilities/cmcurl/multiif.h deleted file mode 100644 index 800aa0f..0000000 --- a/Utilities/cmcurl/multiif.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __MULTIIF_H -#define __MULTIIF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * Prototypes for library-wide functions provided by multi.c - */ -void Curl_expire(struct SessionHandle *data, long milli); - -void Curl_multi_rmeasy(void *multi, CURL *data); - -bool Curl_multi_canPipeline(struct Curl_multi* multi); - -/* the write bits start at bit 16 for the *getsock() bitmap */ -#define GETSOCK_WRITEBITSTART 16 - -#define GETSOCK_BLANK 0 /* no bits set */ - -/* set the bit for the given sock number to make the bitmap for writable */ -#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x))) - -/* set the bit for the given sock number to make the bitmap for readable */ -#define GETSOCK_READSOCK(x) (1 << (x)) - -#endif /* __MULTIIF_H */ diff --git a/Utilities/cmcurl/netrc.c b/Utilities/cmcurl/netrc.c deleted file mode 100644 index 54d1759..0000000 --- a/Utilities/cmcurl/netrc.c +++ /dev/null @@ -1,247 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#ifdef VMS -#include -#endif - -#include -#include "netrc.h" - -#include "strequal.h" -#include "strtok.h" -#include "memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -/* Debug this single source file with: - 'make netrc' then run './netrc'! - - Oh, make sure you have a .netrc file too ;-) - */ - -/* Get user and password from .netrc when given a machine name */ - -enum { - NOTHING, - HOSTFOUND, /* the 'machine' keyword was found */ - HOSTCOMPLETE, /* the machine name following the keyword was found too */ - HOSTVALID, /* this is "our" machine! */ - - HOSTEND /* LAST enum */ -}; - -/* make sure we have room for at least this size: */ -#define LOGINSIZE 64 -#define PASSWORDSIZE 64 - -/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ -int Curl_parsenetrc(char *host, - char *login, - char *password, - char *netrcfile) -{ - FILE *file; - int retcode=1; - int specific_login = (login[0] != 0); - char *home = NULL; - bool home_alloc = FALSE; - bool netrc_alloc = FALSE; - int state=NOTHING; - - char state_login=0; /* Found a login keyword */ - char state_password=0; /* Found a password keyword */ - int state_our_login=FALSE; /* With specific_login, found *our* login name */ - -#define NETRC DOT_CHAR "netrc" - -#ifdef CURLDEBUG - { - /* This is a hack to allow testing. - * If compiled with --enable-debug and CURL_DEBUG_NETRC is defined, - * then it's the path to a substitute .netrc for testing purposes *only* */ - - char *override = curl_getenv("CURL_DEBUG_NETRC"); - - if (override) { - fprintf(stderr, "NETRC: overridden " NETRC " file: %s\n", override); - netrcfile = override; - netrc_alloc = TRUE; - } - } -#endif /* CURLDEBUG */ - if(!netrcfile) { - home = curl_getenv("HOME"); /* portable environment reader */ - if(home) { - home_alloc = TRUE; -#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) - } - else { - struct passwd *pw; - pw= getpwuid(geteuid()); - if (pw) { -#ifdef VMS - home = decc$translate_vms(pw->pw_dir); -#else - home = pw->pw_dir; -#endif - } -#endif - } - - if(!home) - return -1; - - netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC); - if(!netrcfile) { - if(home_alloc) - free(home); - return -1; - } - netrc_alloc = TRUE; - } - - file = fopen(netrcfile, "r"); - if(file) { - char *tok; - char *tok_buf; - bool done=FALSE; - char netrcbuffer[256]; - - while(!done && fgets(netrcbuffer, sizeof(netrcbuffer), file)) { - tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); - while(!done && tok) { - - if (login[0] && password[0]) { - done=TRUE; - break; - } - - switch(state) { - case NOTHING: - if(strequal("machine", tok)) { - /* the next tok is the machine name, this is in itself the - delimiter that starts the stuff entered for this machine, - after this we need to search for 'login' and - 'password'. */ - state=HOSTFOUND; - } - break; - case HOSTFOUND: - if(strequal(host, tok)) { - /* and yes, this is our host! */ - state=HOSTVALID; -#ifdef _NETRC_DEBUG - fprintf(stderr, "HOST: %s\n", tok); -#endif - retcode=0; /* we did find our host */ - } - else - /* not our host */ - state=NOTHING; - break; - case HOSTVALID: - /* we are now parsing sub-keywords concerning "our" host */ - if(state_login) { - if (specific_login) { - state_our_login = strequal(login, tok); - } - else { - strncpy(login, tok, LOGINSIZE-1); -#ifdef _NETRC_DEBUG - fprintf(stderr, "LOGIN: %s\n", login); -#endif - } - state_login=0; - } - else if(state_password) { - if (state_our_login || !specific_login) { - strncpy(password, tok, PASSWORDSIZE-1); -#ifdef _NETRC_DEBUG - fprintf(stderr, "PASSWORD: %s\n", password); -#endif - } - state_password=0; - } - else if(strequal("login", tok)) - state_login=1; - else if(strequal("password", tok)) - state_password=1; - else if(strequal("machine", tok)) { - /* ok, there's machine here go => */ - state = HOSTFOUND; - state_our_login = FALSE; - } - break; - } /* switch (state) */ - - tok = strtok_r(NULL, " \t\n", &tok_buf); - } /* while (tok) */ - } /* while fgets() */ - - fclose(file); - } - - if(home_alloc) - free(home); - if(netrc_alloc) - free(netrcfile); - - return retcode; -} - -#ifdef _NETRC_DEBUG -int main(int argc, char **argv) -{ - char login[64]=""; - char password[64]=""; - - if(argc<2) - return -1; - - if(0 == ParseNetrc(argv[1], login, password)) { - printf("HOST: %s LOGIN: %s PASSWORD: %s\n", - argv[1], login, password); - } -} - -#endif diff --git a/Utilities/cmcurl/netrc.h b/Utilities/cmcurl/netrc.h deleted file mode 100644 index 939c552..0000000 --- a/Utilities/cmcurl/netrc.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __NETRC_H -#define __NETRC_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -int Curl_parsenetrc(char *host, - char *login, - char *password, - char *filename); - /* Assume: password[0]=0, host[0] != 0. - * If login[0] = 0, search for login and password within a machine section - * in the netrc. - * If login[0] != 0, search for password within machine and login. - */ -#endif diff --git a/Utilities/cmcurl/nwlib.c b/Utilities/cmcurl/nwlib.c deleted file mode 100644 index b0eea56..0000000 --- a/Utilities/cmcurl/nwlib.c +++ /dev/null @@ -1,300 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "memory.h" -#include "memdebug.h" - -typedef struct -{ - int _errno; - void *twentybytes; -} libthreaddata_t; - -typedef struct -{ - int x; - int y; - int z; - void *tenbytes; - NXKey_t perthreadkey; /* if -1, no key obtained... */ - NXMutex_t *lock; -} libdata_t; - -int gLibId = -1; -void *gLibHandle = (void *) NULL; -rtag_t gAllocTag = (rtag_t) NULL; -NXMutex_t *gLibLock = (NXMutex_t *) NULL; - -/* internal library function prototypes... */ -int DisposeLibraryData ( void * ); -void DisposeThreadData ( void * ); -int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata ); - - -int _NonAppStart( void *NLMHandle, - void *errorScreen, - const char *cmdLine, - const char *loadDirPath, - size_t uninitializedDataLength, - void *NLMFileHandle, - int (*readRoutineP)( int conn, - void *fileHandle, size_t offset, - size_t nbytes, - size_t *bytesRead, - void *buffer ), - size_t customDataOffset, - size_t customDataSize, - int messageCount, - const char **messages ) -{ - NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); - -#ifndef __GNUC__ -#pragma unused(cmdLine) -#pragma unused(loadDirPath) -#pragma unused(uninitializedDataLength) -#pragma unused(NLMFileHandle) -#pragma unused(readRoutineP) -#pragma unused(customDataOffset) -#pragma unused(customDataSize) -#pragma unused(messageCount) -#pragma unused(messages) -#endif - -/* -** Here we process our command line, post errors (to the error screen), -** perform initializations and anything else we need to do before being able -** to accept calls into us. If we succeed, we return non-zero and the NetWare -** Loader will leave us up, otherwise we fail to load and get dumped. -*/ - gAllocTag = AllocateResourceTag(NLMHandle, - " memory allocations", - AllocSignature); - - if (!gAllocTag) { - OutputToScreen(errorScreen, "Unable to allocate resource tag for " - "library memory allocations.\n"); - return -1; - } - - gLibId = register_library(DisposeLibraryData); - - if (gLibId < -1) { - OutputToScreen(errorScreen, "Unable to register library with kernel.\n"); - return -1; - } - - gLibHandle = NLMHandle; - - gLibLock = NXMutexAlloc(0, 0, &liblock); - - if (!gLibLock) { - OutputToScreen(errorScreen, "Unable to allocate library data lock.\n"); - return -1; - } - - return 0; -} - -/* -** Here we clean up any resources we allocated. Resource tags is a big part -** of what we created, but NetWare doesn't ask us to free those. -*/ -void _NonAppStop( void ) -{ - (void) unregister_library(gLibId); - NXMutexFree(gLibLock); -} - -/* -** This function cannot be the first in the file for if the file is linked -** first, then the check-unload function's offset will be nlmname.nlm+0 -** which is how to tell that there isn't one. When the check function is -** first in the linked objects, it is ambiguous. For this reason, we will -** put it inside this file after the stop function. -** -** Here we check to see if it's alright to ourselves to be unloaded. If not, -** we return a non-zero value. Right now, there isn't any reason not to allow -** it. -*/ -int _NonAppCheckUnload( void ) -{ - return 0; -} - -int GetOrSetUpData(int id, libdata_t **appData, - libthreaddata_t **threadData ) -{ - int err; - libdata_t *app_data; - libthreaddata_t *thread_data; - NXKey_t key; - NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0); - - err = 0; - thread_data = (libthreaddata_t *) NULL; - -/* -** Attempt to get our data for the application calling us. This is where we -** store whatever application-specific information we need to carry in support -** of calling applications. -*/ - app_data = (libdata_t *) get_app_data(id); - - if (!app_data) { -/* -** This application hasn't called us before; set up application AND per-thread -** data. Of course, just in case a thread from this same application is calling -** us simultaneously, we better lock our application data-creation mutex. We -** also need to recheck for data after we acquire the lock because WE might be -** that other thread that was too late to create the data and the first thread -** in will have created it. -*/ - NXLock(gLibLock); - - if (!(app_data = (libdata_t *) get_app_data(id))) { - app_data = (libdata_t *) malloc(sizeof(libdata_t)); - - if (app_data) { - memset(app_data, 0, sizeof(libdata_t)); - - app_data->tenbytes = malloc(10); - app_data->lock = NXMutexAlloc(0, 0, &liblock); - - if (!app_data->tenbytes || !app_data->lock) { - if (app_data->lock) - NXMutexFree(app_data->lock); - - free(app_data); - app_data = (libdata_t *) NULL; - err = ENOMEM; - } - - if (app_data) { -/* -** Here we burn in the application data that we were trying to get by calling -** get_app_data(). Next time we call the first function, we'll get this data -** we're just now setting. We also go on here to establish the per-thread data -** for the calling thread, something we'll have to do on each application -** thread the first time it calls us. -*/ - err = set_app_data(gLibId, app_data); - - if (err) { - free(app_data); - app_data = (libdata_t *) NULL; - err = ENOMEM; - } - else { - /* create key for thread-specific data... */ - err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key); - - if (err) /* (no more keys left?) */ - key = -1; - - app_data->perthreadkey = key; - } - } - } - } - - NXUnlock(gLibLock); - } - - if (app_data) { - key = app_data->perthreadkey; - - if (key != -1 /* couldn't create a key? no thread data */ - && !(err = NXKeyGetValue(key, (void **) &thread_data)) - && !thread_data) { -/* -** Allocate the per-thread data for the calling thread. Regardless of whether -** there was already application data or not, this may be the first call by a -** a new thread. The fact that we allocation 20 bytes on a pointer is not very -** important, this just helps to demonstrate that we can have arbitrarily -** complex per-thread data. -*/ - thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t)); - - if (thread_data) { - thread_data->_errno = 0; - thread_data->twentybytes = malloc(20); - - if (!thread_data->twentybytes) { - free(thread_data); - thread_data = (libthreaddata_t *) NULL; - err = ENOMEM; - } - - if ((err = NXKeySetValue(key, thread_data))) { - free(thread_data->twentybytes); - free(thread_data); - thread_data = (libthreaddata_t *) NULL; - } - } - } - } - - if (appData) - *appData = app_data; - - if (threadData) - *threadData = thread_data; - - return err; -} - -int DisposeLibraryData( void *data) -{ - if (data) { - void *tenbytes = ((libdata_t *) data)->tenbytes; - - if (tenbytes) - free(tenbytes); - - free(data); - } - - return 0; -} - -void DisposeThreadData(void *data) -{ - if (data) { - void *twentybytes = ((libthreaddata_t *) data)->twentybytes; - - if (twentybytes) - free(twentybytes); - - free(data); - } -} diff --git a/Utilities/cmcurl/parsedate.c b/Utilities/cmcurl/parsedate.c deleted file mode 100644 index ef91585..0000000 --- a/Utilities/cmcurl/parsedate.c +++ /dev/null @@ -1,425 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -/* - A brief summary of the date string formats this parser groks: - - RFC 2616 3.3.1 - - Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - - we support dates without week day name: - - 06 Nov 1994 08:49:37 GMT - 06-Nov-94 08:49:37 GMT - Nov 6 08:49:37 1994 - - without the time zone: - - 06 Nov 1994 08:49:37 - 06-Nov-94 08:49:37 - - weird order: - - 1994 Nov 6 08:49:37 (GNU date fails) - GMT 08:49:37 06-Nov-94 Sunday - 94 6 Nov 08:49:37 (GNU date fails) - - time left out: - - 1994 Nov 6 - 06-Nov-94 - Sun Nov 6 94 - - unusual separators: - - 1994.Nov.6 - Sun/Nov/6/94/GMT - - commonly used time zone names: - - Sun, 06 Nov 1994 08:49:37 CET - 06 Nov 1994 08:49:37 EST - - time zones specified using RFC822 style: - - Sun, 12 Sep 2004 15:05:58 -0700 - Sat, 11 Sep 2004 21:32:11 +0200 - - compact numerical date strings: - - 20040912 15:05:58 -0700 - 20040911 +0200 - -*/ -#include "setup.h" -#include -#include -#include - -#ifdef HAVE_STDLIB_H -#include /* for strtol() */ -#endif - -#include - -static time_t Curl_parsedate(const char *date); - -const char * const Curl_wkday[] = -{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; -static const char * const weekday[] = -{ "Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday", "Sunday" }; -const char * const Curl_month[]= -{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -struct tzinfo { - const char *name; - int offset; /* +/- in minutes */ -}; - -/* Here's a bunch of frequently used time zone names. These were supported - by the old getdate parser. */ -#define tDAYZONE -60 /* offset for daylight savings time */ -static const struct tzinfo tz[]= { - {"GMT", 0}, /* Greenwich Mean */ - {"UTC", 0}, /* Universal (Coordinated) */ - {"WET", 0}, /* Western European */ - {"BST", 0 tDAYZONE}, /* British Summer */ - {"WAT", 60}, /* West Africa */ - {"AST", 240}, /* Atlantic Standard */ - {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */ - {"EST", 300}, /* Eastern Standard */ - {"EDT", 300 tDAYZONE}, /* Eastern Daylight */ - {"CST", 360}, /* Central Standard */ - {"CDT", 360 tDAYZONE}, /* Central Daylight */ - {"MST", 420}, /* Mountain Standard */ - {"MDT", 420 tDAYZONE}, /* Mountain Daylight */ - {"PST", 480}, /* Pacific Standard */ - {"PDT", 480 tDAYZONE}, /* Pacific Daylight */ - {"YST", 540}, /* Yukon Standard */ - {"YDT", 540 tDAYZONE}, /* Yukon Daylight */ - {"HST", 600}, /* Hawaii Standard */ - {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */ - {"CAT", 600}, /* Central Alaska */ - {"AHST", 600}, /* Alaska-Hawaii Standard */ - {"NT", 660}, /* Nome */ - {"IDLW", 720}, /* International Date Line West */ - {"CET", -60}, /* Central European */ - {"MET", -60}, /* Middle European */ - {"MEWT", -60}, /* Middle European Winter */ - {"MEST", -60 tDAYZONE}, /* Middle European Summer */ - {"CEST", -60 tDAYZONE}, /* Central European Summer */ - {"MESZ", -60 tDAYZONE}, /* Middle European Summer */ - {"FWT", -60}, /* French Winter */ - {"FST", -60 tDAYZONE}, /* French Summer */ - {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ - {"WAST", -420}, /* West Australian Standard */ - {"WADT", -420 tDAYZONE}, /* West Australian Daylight */ - {"CCT", -480}, /* China Coast, USSR Zone 7 */ - {"JST", -540}, /* Japan Standard, USSR Zone 8 */ - {"EAST", -600}, /* Eastern Australian Standard */ - {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */ - {"GST", -600}, /* Guam Standard, USSR Zone 9 */ - {"NZT", -720}, /* New Zealand */ - {"NZST", -720}, /* New Zealand Standard */ - {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */ - {"IDLE", -720}, /* International Date Line East */ -}; - -/* returns: - -1 no day - 0 monday - 6 sunday -*/ - -static int checkday(char *check, size_t len) -{ - int i; - const char * const *what; - bool found= FALSE; - if(len > 3) - what = &weekday[0]; - else - what = &Curl_wkday[0]; - for(i=0; i<7; i++) { - if(curl_strequal(check, what[0])) { - found=TRUE; - break; - } - what++; - } - return found?i:-1; -} - -static int checkmonth(char *check) -{ - int i; - const char * const *what; - bool found= FALSE; - - what = &Curl_month[0]; - for(i=0; i<12; i++) { - if(curl_strequal(check, what[0])) { - found=TRUE; - break; - } - what++; - } - return found?i:-1; /* return the offset or -1, no real offset is -1 */ -} - -/* return the time zone offset between GMT and the input one, in number - of seconds or -1 if the timezone wasn't found/legal */ - -static int checktz(char *check) -{ - unsigned int i; - const struct tzinfo *what; - bool found= FALSE; - - what = tz; - for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(curl_strequal(check, what->name)) { - found=TRUE; - break; - } - what++; - } - return found?what->offset*60:-1; -} - -static void skip(const char **date) -{ - /* skip everything that aren't letters or digits */ - while(**date && !ISALNUM(**date)) - (*date)++; -} - -enum assume { - DATE_MDAY, - DATE_YEAR, - DATE_TIME -}; - -static time_t Curl_parsedate(const char *date) -{ - time_t t = 0; - int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ - int monnum=-1; /* month of the year number, 0-11 */ - int mdaynum=-1; /* day of month, 1 - 31 */ - int hournum=-1; - int minnum=-1; - int secnum=-1; - int yearnum=-1; - int tzoff=-1; - struct tm tm; - enum assume dignext = DATE_MDAY; - const char *indate = date; /* save the original pointer */ - int part = 0; /* max 6 parts */ - - while(*date && (part < 6)) { - bool found=FALSE; - - skip(&date); - - if(ISALPHA(*date)) { - /* a name coming up */ - char buf[32]=""; - size_t len; - sscanf(date, "%31[A-Za-z]", buf); - len = strlen(buf); - - if(wdaynum == -1) { - wdaynum = checkday(buf, len); - if(wdaynum != -1) - found = TRUE; - } - if(!found && (monnum == -1)) { - monnum = checkmonth(buf); - if(monnum != -1) - found = TRUE; - } - - if(!found && (tzoff == -1)) { - /* this just must be a time zone string */ - tzoff = checktz(buf); - if(tzoff != -1) - found = TRUE; - } - - if(!found) - return -1; /* bad string */ - - date += len; - } - else if(ISDIGIT(*date)) { - /* a digit */ - int val; - char *end; - if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { - /* time stamp! */ - date += 8; - found = TRUE; - } - else { - val = (int)strtol(date, &end, 10); - - if((tzoff == -1) && - ((end - date) == 4) && - (val < 1300) && - (indate< date) && - ((date[-1] == '+' || date[-1] == '-'))) { - /* four digits and a value less than 1300 and it is preceeded with - a plus or minus. This is a time zone indication. */ - found = TRUE; - tzoff = (val/100 * 60 + val%100)*60; - - /* the + and - prefix indicates the local time compared to GMT, - this we need ther reversed math to get what we want */ - tzoff = date[-1]=='+'?-tzoff:tzoff; - } - - if(((end - date) == 8) && - (yearnum == -1) && - (monnum == -1) && - (mdaynum == -1)) { - /* 8 digits, no year, month or day yet. This is YYYYMMDD */ - found = TRUE; - yearnum = val/10000; - monnum = (val%10000)/100-1; /* month is 0 - 11 */ - mdaynum = val%100; - } - - if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { - if((val > 0) && (val<32)) { - mdaynum = val; - found = TRUE; - } - dignext = DATE_YEAR; - } - - if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { - yearnum = val; - found = TRUE; - if(yearnum < 1900) { - if (yearnum > 70) - yearnum += 1900; - else - yearnum += 2000; - } - if(mdaynum == -1) - dignext = DATE_MDAY; - } - - if(!found) - return -1; - - date = end; - } - } - - part++; - } - - if(-1 == secnum) - secnum = minnum = hournum = 0; /* no time, make it zero */ - - if((-1 == mdaynum) || - (-1 == monnum) || - (-1 == yearnum)) - /* lacks vital info, fail */ - return -1; - -#if SIZEOF_TIME_T < 5 - /* 32 bit time_t can only hold dates to the beginning of 2038 */ - if(yearnum > 2037) - return 0x7fffffff; -#endif - - tm.tm_sec = secnum; - tm.tm_min = minnum; - tm.tm_hour = hournum; - tm.tm_mday = mdaynum; - tm.tm_mon = monnum; - tm.tm_year = yearnum - 1900; - tm.tm_wday = 0; - tm.tm_yday = 0; - tm.tm_isdst = 0; - - /* mktime() returns a time_t. time_t is often 32 bits, even on many - architectures that feature 64 bit 'long'. - - Some systems have 64 bit time_t and deal with years beyond 2038. However, - even some of the systems with 64 bit time_t returns -1 for dates beyond - 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) - */ - t = mktime(&tm); - - /* time zone adjust (cast t to int to compare to negative one) */ - if(-1 != (int)t) { - struct tm *gmt; - long delta; - time_t t2; - -#ifdef HAVE_GMTIME_R - /* thread-safe version */ - struct tm keeptime2; - gmt = (struct tm *)gmtime_r(&t, &keeptime2); - if(!gmt) - return -1; /* illegal date/time */ - t2 = mktime(gmt); -#else - /* It seems that at least the MSVC version of mktime() doesn't work - properly if it gets the 'gmt' pointer passed in (which is a pointer - returned from gmtime() pointing to static memory), so instead we copy - the tm struct to a local struct and pass a pointer to that struct as - input to mktime(). */ - struct tm gmt2; - gmt = gmtime(&t); /* use gmtime_r() if available */ - if(!gmt) - return -1; /* illegal date/time */ - gmt2 = *gmt; - t2 = mktime(&gmt2); -#endif - - /* Add the time zone diff (between the given timezone and GMT) and the - diff between the local time zone and GMT. */ - delta = (long)((tzoff!=-1?tzoff:0) + (t - t2)); - - if((delta>0) && (t + delta < t)) - return -1; /* time_t overflow */ - - t += delta; - } - - return t; -} - -time_t curl_getdate(const char *p, const time_t *now) -{ - (void)now; - return Curl_parsedate(p); -} diff --git a/Utilities/cmcurl/parsedate.h b/Utilities/cmcurl/parsedate.h deleted file mode 100644 index b29fe9b..0000000 --- a/Utilities/cmcurl/parsedate.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __PARSEDATE_H -#define __PARSEDATE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -extern const char * const Curl_wkday[7]; -extern const char * const Curl_month[12]; - -#endif diff --git a/Utilities/cmcurl/progress.c b/Utilities/cmcurl/progress.c deleted file mode 100644 index 5ba829a..0000000 --- a/Utilities/cmcurl/progress.c +++ /dev/null @@ -1,424 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#if defined(__EMX__) -#include -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero - byte) */ -static void time2str(char *r, long t) -{ - long h; - if(!t) { - strcpy(r, "--:--:--"); - return; - } - h = (t/3600); - if(h <= 99) { - long m = (t-(h*3600))/60; - long s = (t-(h*3600)-(m*60)); - snprintf(r, 9, "%2ld:%02ld:%02ld",h,m,s); - } - else { - /* this equals to more than 99 hours, switch to a more suitable output - format to fit within the limits. */ - if(h/24 <= 999) - snprintf(r, 9, "%3ldd %02ldh", h/24, h-(h/24)*24); - else - snprintf(r, 9, "%7ldd", h/24); - } -} - -/* The point of this function would be to return a string of the input data, - but never longer than 5 columns (+ one zero byte). - Add suffix k, M, G when suitable... */ -static char *max5data(curl_off_t bytes, char *max5) -{ -#define ONE_KILOBYTE 1024 -#define ONE_MEGABYTE (1024* ONE_KILOBYTE) -#define ONE_GIGABYTE (1024* ONE_MEGABYTE) -#define ONE_TERRABYTE ((curl_off_t)1024* ONE_GIGABYTE) -#define ONE_PETABYTE ((curl_off_t)1024* ONE_TERRABYTE) - - if(bytes < 100000) { - snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes); - } - else if(bytes < (10000*ONE_KILOBYTE)) { - snprintf(max5, 6, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE)); - } - else if(bytes < (100*ONE_MEGABYTE)) { - /* 'XX.XM' is good as long as we're less than 100 megs */ - snprintf(max5, 6, "%2d.%0dM", - (int)(bytes/ONE_MEGABYTE), - (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) ); - } -#if SIZEOF_CURL_OFF_T > 4 - else if(bytes < ( (curl_off_t)10000*ONE_MEGABYTE)) - /* 'XXXXM' is good until we're at 10000MB or above */ - snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE)); - - else if(bytes < (curl_off_t)100*ONE_GIGABYTE) - /* 10000 MB - 100 GB, we show it as XX.XG */ - snprintf(max5, 6, "%2d.%0dG", - (int)(bytes/ONE_GIGABYTE), - (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) ); - - else if(bytes < (curl_off_t)10000 * ONE_GIGABYTE) - /* up to 10000GB, display without decimal: XXXXG */ - snprintf(max5, 6, "%4dG", (int)(bytes/ONE_GIGABYTE)); - - else if(bytes < (curl_off_t)10000 * ONE_TERRABYTE) - /* up to 10000TB, display without decimal: XXXXT */ - snprintf(max5, 6, "%4dT", (int)(bytes/ONE_TERRABYTE)); - else { - /* up to 10000PB, display without decimal: XXXXP */ - snprintf(max5, 6, "%4dP", (int)(bytes/ONE_PETABYTE)); - - /* 16384 petabytes (16 exabytes) is maximum a 64 bit number can hold, - but this type is signed so 8192PB will be max.*/ - } - -#else - else - snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE)); -#endif - - return max5; -} - -/* - - New proposed interface, 9th of February 2000: - - pgrsStartNow() - sets start time - pgrsSetDownloadSize(x) - known expected download size - pgrsSetUploadSize(x) - known expected upload size - pgrsSetDownloadCounter() - amount of data currently downloaded - pgrsSetUploadCounter() - amount of data currently uploaded - pgrsUpdate() - show progress - pgrsDone() - transfer complete - -*/ - -void Curl_pgrsDone(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - data->progress.lastshow=0; - Curl_pgrsUpdate(conn); /* the final (forced) update */ - - data->progress.speeder_c = 0; /* reset the progress meter display */ -} - -/* reset all times except redirect */ -void Curl_pgrsResetTimes(struct SessionHandle *data) -{ - data->progress.t_nslookup = 0.0; - data->progress.t_connect = 0.0; - data->progress.t_pretransfer = 0.0; - data->progress.t_starttransfer = 0.0; -} - -void Curl_pgrsTime(struct SessionHandle *data, timerid timer) -{ - switch(timer) { - default: - case TIMER_NONE: - /* mistake filter */ - break; - case TIMER_STARTSINGLE: - /* This is set at the start of a single fetch */ - data->progress.t_startsingle = Curl_tvnow(); - break; - - case TIMER_NAMELOOKUP: - data->progress.t_nslookup = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); - break; - case TIMER_CONNECT: - data->progress.t_connect = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); - break; - case TIMER_PRETRANSFER: - data->progress.t_pretransfer = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); - break; - case TIMER_STARTTRANSFER: - data->progress.t_starttransfer = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); - break; - case TIMER_POSTRANSFER: - /* this is the normal end-of-transfer thing */ - break; - case TIMER_REDIRECT: - data->progress.t_redirect = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.start); - break; - } -} - -void Curl_pgrsStartNow(struct SessionHandle *data) -{ - data->progress.speeder_c = 0; /* reset the progress meter display */ - data->progress.start = Curl_tvnow(); -} - -void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) -{ - data->progress.downloaded = size; -} - -void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size) -{ - data->progress.uploaded = size; -} - -void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) -{ - data->progress.size_dl = size; - if(size > 0) - data->progress.flags |= PGRS_DL_SIZE_KNOWN; - else - data->progress.flags &= ~PGRS_DL_SIZE_KNOWN; -} - -void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size) -{ - data->progress.size_ul = size; - if(size > 0) - data->progress.flags |= PGRS_UL_SIZE_KNOWN; - else - data->progress.flags &= ~PGRS_UL_SIZE_KNOWN; -} - -int Curl_pgrsUpdate(struct connectdata *conn) -{ - struct timeval now; - int result; - char max5[6][10]; - int dlpercen=0; - int ulpercen=0; - int total_percen=0; - curl_off_t total_transfer; - curl_off_t total_expected_transfer; - long timespent; - struct SessionHandle *data = conn->data; - int nowindex = data->progress.speeder_c% CURR_TIME; - int checkindex; - int countindex; /* amount of seconds stored in the speeder array */ - char time_left[10]; - char time_total[10]; - char time_spent[10]; - long ulestimate=0; - long dlestimate=0; - long total_estimate; - - if(data->progress.flags & PGRS_HIDE) - ; /* We do enter this function even if we don't wanna see anything, since - this is were lots of the calculations are being made that will be used - even when not displayed! */ - else if(!(data->progress.flags & PGRS_HEADERS_OUT)) { - if (!data->progress.callback) { - if(data->reqdata.resume_from) - fprintf(data->set.err, - "** Resuming transfer from byte position %" FORMAT_OFF_T - "\n", - data->reqdata.resume_from); - fprintf(data->set.err, - " %% Total %% Received %% Xferd Average Speed Time Time Time Current\n" - " Dload Upload Total Spent Left Speed\n"); - } - data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */ - } - - now = Curl_tvnow(); /* what time is it */ - - /* The time spent so far (from the start) */ - data->progress.timespent = Curl_tvdiff_secs(now, data->progress.start); - timespent = (long)data->progress.timespent; - - /* The average download speed this far */ - data->progress.dlspeed = (curl_off_t) - ((double)data->progress.downloaded/ - (data->progress.timespent>0?data->progress.timespent:1)); - - /* The average upload speed this far */ - data->progress.ulspeed = (curl_off_t) - ((double)data->progress.uploaded/ - (data->progress.timespent>0?data->progress.timespent:1)); - - if(data->progress.lastshow == Curl_tvlong(now)) - return 0; /* never update this more than once a second if the end isn't - reached */ - data->progress.lastshow = now.tv_sec; - - /* Let's do the "current speed" thing, which should use the fastest - of the dl/ul speeds. Store the fasted speed at entry 'nowindex'. */ - data->progress.speeder[ nowindex ] = - data->progress.downloaded>data->progress.uploaded? - data->progress.downloaded:data->progress.uploaded; - - /* remember the exact time for this moment */ - data->progress.speeder_time [ nowindex ] = now; - - /* advance our speeder_c counter, which is increased every time we get - here and we expect it to never wrap as 2^32 is a lot of seconds! */ - data->progress.speeder_c++; - - /* 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've filled in three entries etc. */ - countindex = ((data->progress.speeder_c>=CURR_TIME)? - CURR_TIME:data->progress.speeder_c) - 1; - - /* first of all, we don't do this if there's no counted seconds yet */ - if(countindex) { - long span_ms; - - /* Get the index position to compare with the 'nowindex' position. - Get the oldest entry possible. While we have less than CURR_TIME - entries, the first entry will remain the oldest. */ - checkindex = (data->progress.speeder_c>=CURR_TIME)? - data->progress.speeder_c%CURR_TIME:0; - - /* Figure out the exact time for the time span */ - span_ms = Curl_tvdiff(now, - data->progress.speeder_time[checkindex]); - if(0 == span_ms) - span_ms=1; /* at least one millisecond MUST have passed */ - - /* Calculate the average speed the last 'span_ms' milliseconds */ - { - curl_off_t amount = data->progress.speeder[nowindex]- - data->progress.speeder[checkindex]; - - if(amount > 4294967 /* 0xffffffff/1000 */) - /* the 'amount' value is bigger than would fit in 32 bits if - multiplied with 1000, so we use the double math for this */ - data->progress.current_speed = (curl_off_t) - ((double)amount/((double)span_ms/1000.0)); - else - /* the 'amount' value is small enough to fit within 32 bits even - when multiplied with 1000 */ - data->progress.current_speed = amount*1000/span_ms; - } - } - else - /* the first second we use the main average */ - data->progress.current_speed = - (data->progress.ulspeed>data->progress.dlspeed)? - data->progress.ulspeed:data->progress.dlspeed; - - if(data->progress.flags & PGRS_HIDE) - return 0; - - else if(data->set.fprogress) { - /* There's a callback set, so we call that instead of writing - anything ourselves. This really is the way to go. */ - result= data->set.fprogress(data->set.progress_client, - (double)data->progress.size_dl, - (double)data->progress.downloaded, - (double)data->progress.size_ul, - (double)data->progress.uploaded); - if(result) - failf(data, "Callback aborted"); - return result; - } - - /* Figure out the estimated time of arrival for the upload */ - if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && - (data->progress.ulspeed>0) && - (data->progress.size_ul > 100) ) { - ulestimate = (long)(data->progress.size_ul / data->progress.ulspeed); - ulpercen = (int)(100*(data->progress.uploaded/100) / - (data->progress.size_ul/100) ); - } - - /* ... and the download */ - if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && - (data->progress.dlspeed>0) && - (data->progress.size_dl>100)) { - dlestimate = (long)(data->progress.size_dl / data->progress.dlspeed); - dlpercen = (int)(100*(data->progress.downloaded/100) / - (data->progress.size_dl/100)); - } - - /* Now figure out which of them that is slower and use for the for - total estimate! */ - total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; - - /* create the three time strings */ - 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 transfered */ - 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 transfered this much so far */ - total_transfer = data->progress.downloaded + data->progress.uploaded; - - /* Get the percentage of data transfered so far */ - if(total_expected_transfer > 100) - total_percen=(int)(100*(total_transfer/100) / - (total_expected_transfer/100) ); - - fprintf(data->set.err, - "\r%3d %s %3d %s %3d %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(data->progress.current_speed, max5[5]) /* current speed */ - ); - - /* we flush the output stream to make it appear as soon as possible */ - fflush(data->set.err); - - return 0; -} diff --git a/Utilities/cmcurl/progress.h b/Utilities/cmcurl/progress.h deleted file mode 100644 index ad9d662..0000000 --- a/Utilities/cmcurl/progress.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef __PROGRESS_H -#define __PROGRESS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "timeval.h" - - -typedef enum { - TIMER_NONE, - TIMER_NAMELOOKUP, - TIMER_CONNECT, - TIMER_PRETRANSFER, - TIMER_STARTTRANSFER, - TIMER_POSTRANSFER, - TIMER_STARTSINGLE, - TIMER_REDIRECT, - TIMER_LAST /* must be last */ -} timerid; - -void Curl_pgrsDone(struct connectdata *); -void Curl_pgrsStartNow(struct SessionHandle *data); -void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size); -int Curl_pgrsUpdate(struct connectdata *); -void Curl_pgrsResetTimes(struct SessionHandle *data); -void Curl_pgrsTime(struct SessionHandle *data, timerid timer); - - -/* Don't show progress for sizes smaller than: */ -#define LEAST_SIZE_PROGRESS BUFSIZE - -#define PROGRESS_DOWNLOAD (1<<0) -#define PROGRESS_UPLOAD (1<<1) -#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD) - -#define PGRS_SHOW_DL (1<<0) -#define PGRS_SHOW_UL (1<<1) -#define PGRS_DONE_DL (1<<2) -#define PGRS_DONE_UL (1<<3) -#define PGRS_HIDE (1<<4) -#define PGRS_UL_SIZE_KNOWN (1<<5) -#define PGRS_DL_SIZE_KNOWN (1<<6) - -#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */ - - -#endif /* __PROGRESS_H */ diff --git a/Utilities/cmcurl/security.c b/Utilities/cmcurl/security.c deleted file mode 100644 index 4c9aed8..0000000 --- a/Utilities/cmcurl/security.c +++ /dev/null @@ -1,493 +0,0 @@ -/* This source code was modified by Martin Hedenfalk for - * use in Curl. His latest changes were done 2000-09-18. - * - * It has since been patched and modified a lot by Daniel Stenberg - * to make it better applied to curl conditions, and to make - * it not use globals, pollute name space and more. This source code awaits a - * rewrite to work around the paragraph 2 in the BSD licenses as explained - * below. - * - * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * 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. */ - -#include "setup.h" - -#ifndef CURL_DISABLE_FTP -#ifdef HAVE_KRB4 - -#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */ -#include - -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "urldata.h" -#include "krb4.h" -#include "base64.h" -#include "sendf.h" -#include "ftp.h" -#include "memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#define min(a, b) ((a) < (b) ? (a) : (b)) - -static const struct { - enum protection_level level; - const char *name; -} level_names[] = { - { prot_clear, "clear" }, - { prot_safe, "safe" }, - { prot_confidential, "confidential" }, - { prot_private, "private" } -}; - -static enum protection_level -name_to_level(const char *name) -{ - int i; - for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) - if(curl_strnequal(level_names[i].name, name, strlen(name))) - return level_names[i].level; - return (enum protection_level)-1; -} - -static const struct Curl_sec_client_mech * const mechs[] = { -#ifdef KRB5 - /* not supported */ -#endif -#ifdef HAVE_KRB4 - &Curl_krb4_client_mech, -#endif - NULL -}; - -int -Curl_sec_getc(struct connectdata *conn, FILE *F) -{ - if(conn->sec_complete && conn->data_prot) { - char c; - if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0) - return EOF; - return c; - } - else - return getc(F); -} - -static int -block_read(int fd, void *buf, size_t len) -{ - unsigned char *p = buf; - int b; - while(len) { - b = read(fd, p, len); - if (b == 0) - return 0; - else if (b < 0) - return -1; - len -= b; - p += b; - } - return p - (unsigned char*)buf; -} - -static int -block_write(int fd, void *buf, size_t len) -{ - unsigned char *p = buf; - int b; - while(len) { - b = write(fd, p, len); - if(b < 0) - return -1; - len -= b; - p += b; - } - return p - (unsigned char*)buf; -} - -static int -sec_get_data(struct connectdata *conn, - int fd, struct krb4buffer *buf) -{ - int len; - int b; - - b = block_read(fd, &len, sizeof(len)); - if (b == 0) - return 0; - else if (b < 0) - return -1; - len = ntohl(len); - buf->data = realloc(buf->data, len); - b = block_read(fd, buf->data, len); - if (b == 0) - return 0; - else if (b < 0) - return -1; - buf->size = (conn->mech->decode)(conn->app_data, buf->data, len, - conn->data_prot, conn); - buf->index = 0; - return 0; -} - -static size_t -buffer_read(struct krb4buffer *buf, void *data, size_t len) -{ - len = min(len, buf->size - buf->index); - memcpy(data, (char*)buf->data + buf->index, len); - buf->index += len; - return len; -} - -static size_t -buffer_write(struct krb4buffer *buf, void *data, size_t len) -{ - if(buf->index + len > buf->size) { - void *tmp; - if(buf->data == NULL) - tmp = malloc(1024); - else - tmp = realloc(buf->data, buf->index + len); - if(tmp == NULL) - return -1; - buf->data = tmp; - buf->size = buf->index + len; - } - memcpy((char*)buf->data + buf->index, data, len); - buf->index += len; - return len; -} - -int -Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length) -{ - size_t len; - int rx = 0; - - if(conn->sec_complete == 0 || conn->data_prot == 0) - return read(fd, buffer, length); - - if(conn->in_buffer.eof_flag){ - conn->in_buffer.eof_flag = 0; - return 0; - } - - len = buffer_read(&conn->in_buffer, buffer, length); - length -= len; - rx += len; - buffer = (char*)buffer + len; - - while(length) { - if(sec_get_data(conn, fd, &conn->in_buffer) < 0) - return -1; - if(conn->in_buffer.size == 0) { - if(rx) - conn->in_buffer.eof_flag = 1; - return rx; - } - len = buffer_read(&conn->in_buffer, buffer, length); - length -= len; - rx += len; - buffer = (char*)buffer + len; - } - return rx; -} - -static int -sec_send(struct connectdata *conn, int fd, char *from, int length) -{ - int bytes; - void *buf; - bytes = (conn->mech->encode)(conn->app_data, from, length, conn->data_prot, - &buf, conn); - bytes = htonl(bytes); - block_write(fd, &bytes, sizeof(bytes)); - block_write(fd, buf, ntohl(bytes)); - free(buf); - return length; -} - -int -Curl_sec_fflush_fd(struct connectdata *conn, int fd) -{ - if(conn->data_prot != prot_clear) { - if(conn->out_buffer.index > 0){ - Curl_sec_write(conn, fd, - conn->out_buffer.data, conn->out_buffer.index); - conn->out_buffer.index = 0; - } - sec_send(conn, fd, NULL, 0); - } - return 0; -} - -int -Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length) -{ - int len = conn->buffer_size; - int tx = 0; - - if(conn->data_prot == prot_clear) - return write(fd, buffer, length); - - len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len); - while(length){ - if(length < len) - len = length; - sec_send(conn, fd, buffer, len); - length -= len; - buffer += len; - tx += len; - } - return tx; -} - -ssize_t -Curl_sec_send(struct connectdata *conn, int num, char *buffer, int length) -{ - curl_socket_t fd = conn->sock[num]; - return (ssize_t)Curl_sec_write(conn, fd, buffer, length); -} - -int -Curl_sec_putc(struct connectdata *conn, int c, FILE *F) -{ - char ch = c; - if(conn->data_prot == prot_clear) - return putc(c, F); - - buffer_write(&conn->out_buffer, &ch, 1); - if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) { - Curl_sec_write(conn, fileno(F), conn->out_buffer.data, - conn->out_buffer.index); - conn->out_buffer.index = 0; - } - return c; -} - -int -Curl_sec_read_msg(struct connectdata *conn, char *s, int level) -{ - int len; - unsigned char *buf; - int code; - - len = Curl_base64_decode(s + 4, &buf); /* XXX */ - if(len > 0) - len = (conn->mech->decode)(conn->app_data, buf, len, level, conn); - else - return -1; - - if(len < 0) { - free(buf); - return -1; - } - - buf[len] = '\0'; - - if(buf[3] == '-') - code = 0; - else - sscanf((char *)buf, "%d", &code); - if(buf[len-1] == '\n') - buf[len-1] = '\0'; - strcpy(s, (char *)buf); - free(buf); - return code; -} - -enum protection_level -Curl_set_command_prot(struct connectdata *conn, enum protection_level level) -{ - enum protection_level old = conn->command_prot; - conn->command_prot = level; - return old; -} - -static int -sec_prot_internal(struct connectdata *conn, int level) -{ - char *p; - unsigned int s = 1048576; - ssize_t nread; - - if(!conn->sec_complete){ - infof(conn->data, "No security data exchange has taken place.\n"); - return -1; - } - - if(level){ - int code; - if(Curl_ftpsendf(conn, "PBSZ %u", s)) - return -1; - - if(Curl_GetFTPResponse(&nread, conn, &code)) - return -1; - - if(code/100 != '2'){ - failf(conn->data, "Failed to set protection buffer size."); - return -1; - } - conn->buffer_size = s; - - p = strstr(conn->data->state.buffer, "PBSZ="); - if(p) - sscanf(p, "PBSZ=%u", &s); - if(s < conn->buffer_size) - conn->buffer_size = s; - } - - if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"])) - return -1; - - if(Curl_GetFTPResponse(&nread, conn, NULL)) - return -1; - - if(conn->data->state.buffer[0] != '2'){ - failf(conn->data, "Failed to set protection level."); - return -1; - } - - conn->data_prot = (enum protection_level)level; - return 0; -} - -void -Curl_sec_set_protection_level(struct connectdata *conn) -{ - if(conn->sec_complete && conn->data_prot != conn->request_data_prot) - sec_prot_internal(conn, conn->request_data_prot); -} - - -int -Curl_sec_request_prot(struct connectdata *conn, const char *level) -{ - int l = name_to_level(level); - if(l == -1) - return -1; - conn->request_data_prot = (enum protection_level)l; - return 0; -} - -int -Curl_sec_login(struct connectdata *conn) -{ - int ret; - const struct Curl_sec_client_mech * const *m; - ssize_t nread; - struct SessionHandle *data=conn->data; - int ftpcode; - - for(m = mechs; *m && (*m)->name; m++) { - void *tmp; - - tmp = realloc(conn->app_data, (*m)->size); - if (tmp == NULL) { - failf (data, "realloc %u failed", (*m)->size); - return -1; - } - conn->app_data = tmp; - - if((*m)->init && (*(*m)->init)(conn->app_data) != 0) { - infof(data, "Skipping %s...\n", (*m)->name); - continue; - } - infof(data, "Trying %s...\n", (*m)->name); - - if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name)) - return -1; - - if(Curl_GetFTPResponse(&nread, conn, &ftpcode)) - return -1; - - if(conn->data->state.buffer[0] != '3'){ - switch(ftpcode) { - case 504: - infof(data, - "%s is not supported by the server.\n", (*m)->name); - break; - case 534: - infof(data, "%s rejected as security mechanism.\n", (*m)->name); - break; - default: - if(conn->data->state.buffer[0] == '5') { - infof(data, "The server doesn't support the FTP " - "security extensions.\n"); - return -1; - } - break; - } - continue; - } - - ret = (*(*m)->auth)(conn->app_data, conn); - - if(ret == AUTH_CONTINUE) - continue; - else if(ret != AUTH_OK){ - /* mechanism is supposed to output error string */ - return -1; - } - conn->mech = *m; - conn->sec_complete = 1; - conn->command_prot = prot_safe; - break; - } - - return *m == NULL; -} - -void -Curl_sec_end(struct connectdata *conn) -{ - if (conn->mech != NULL) { - if(conn->mech->end) - (conn->mech->end)(conn->app_data); - memset(conn->app_data, 0, conn->mech->size); - free(conn->app_data); - conn->app_data = NULL; - } - conn->sec_complete = 0; - conn->data_prot = (enum protection_level)0; - conn->mech=NULL; -} - -#endif /* HAVE_KRB4 */ -#endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/select.c b/Utilities/cmcurl/select.c deleted file mode 100644 index 82f9dc2..0000000 --- a/Utilities/cmcurl/select.c +++ /dev/null @@ -1,315 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifndef HAVE_SELECT -#error "We can't compile without select() support!" -#endif - -#if defined(__BEOS__) -/* BeOS has FD_SET defined in socket.h */ -#include -#endif - -#ifdef __MSDOS__ -#include /* delay() */ -#endif - -#include - -#include "urldata.h" -#include "connect.h" -#include "select.h" - -#if defined(USE_WINSOCK) || defined(TPF) -#define VERIFY_SOCK(x) /* sockets are not in range [0..FD_SETSIZE] */ -#else -#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) -#define VERIFY_SOCK(x) do { \ - if(!VALID_SOCK(x)) { \ - errno = EINVAL; \ - return -1; \ - } \ -} while(0) -#endif - -/* - * This is an internal function used for waiting for read or write - * events on single file descriptors. It attempts to replace select() - * in order to avoid limits with FD_SETSIZE. - * - * Return values: - * -1 = system call error - * 0 = timeout - * CSELECT_IN | CSELECT_OUT | CSELECT_ERR - */ -int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms) -{ -#if (defined(HAVE_POLL) && !defined(_POLL_EMUL_H_)) || defined(CURL_HAVE_WSAPOLL) - struct pollfd pfd[2]; - int num; - int r; - int ret; - - num = 0; - if (readfd != CURL_SOCKET_BAD) { - pfd[num].fd = readfd; - pfd[num].events = POLLIN; - num++; - } - if (writefd != CURL_SOCKET_BAD) { - pfd[num].fd = writefd; - pfd[num].events = POLLOUT; - num++; - } - -#if defined(HAVE_POLL) && !defined(_POLL_EMUL_H_) - do { - r = poll(pfd, num, timeout_ms); - } while((r == -1) && (errno == EINTR)); -#else - r = WSAPoll(pfd, num, timeout_ms); -#endif - - if (r < 0) - return -1; - if (r == 0) - return 0; - - ret = 0; - num = 0; - if (readfd != CURL_SOCKET_BAD) { - if (pfd[num].revents & (POLLIN|POLLHUP)) - ret |= CSELECT_IN; - if (pfd[num].revents & POLLERR) { -#ifdef __CYGWIN__ - /* Cygwin 1.5.21 needs this hack to pass test 160 */ - if (errno == EINPROGRESS) - ret |= CSELECT_IN; - else -#endif - ret |= CSELECT_ERR; - } - num++; - } - if (writefd != CURL_SOCKET_BAD) { - if (pfd[num].revents & POLLOUT) - ret |= CSELECT_OUT; - if (pfd[num].revents & (POLLERR|POLLHUP)) - ret |= CSELECT_ERR; - } - - return ret; -#else - struct timeval timeout; - fd_set fds_read; - fd_set fds_write; - fd_set fds_err; - curl_socket_t maxfd; - int r; - int ret; - - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - - if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { - /* According to POSIX we should pass in NULL pointers if we don't want to - wait for anything in particular but just use the timeout function. - Windows however returns immediately if done so. I copied the MSDOS - delay() use from src/main.c that already had this work-around. */ -#ifdef WIN32 - Sleep(timeout_ms); -#elif defined(__MSDOS__) - delay(timeout_ms); -#else - select(0, NULL, NULL, NULL, &timeout); -#endif - return 0; - } - - FD_ZERO(&fds_err); - maxfd = (curl_socket_t)-1; - - FD_ZERO(&fds_read); - if (readfd != CURL_SOCKET_BAD) { - VERIFY_SOCK(readfd); - FD_SET(readfd, &fds_read); - FD_SET(readfd, &fds_err); - maxfd = readfd; - } - - FD_ZERO(&fds_write); - if (writefd != CURL_SOCKET_BAD) { - VERIFY_SOCK(writefd); - FD_SET(writefd, &fds_write); - FD_SET(writefd, &fds_err); - if (writefd > maxfd) - maxfd = writefd; - } - - do { - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); - } while((r == -1) && (Curl_sockerrno() == EINTR)); - - if (r < 0) - return -1; - if (r == 0) - return 0; - - ret = 0; - if (readfd != CURL_SOCKET_BAD) { - if (FD_ISSET(readfd, &fds_read)) - ret |= CSELECT_IN; - if (FD_ISSET(readfd, &fds_err)) - ret |= CSELECT_ERR; - } - if (writefd != CURL_SOCKET_BAD) { - if (FD_ISSET(writefd, &fds_write)) - ret |= CSELECT_OUT; - if (FD_ISSET(writefd, &fds_err)) - ret |= CSELECT_ERR; - } - - return ret; -#endif -} - -/* - * 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 too large for FD_SETSIZE. - * - * Return values: - * -1 = system call error or fd >= FD_SETSIZE - * 0 = timeout - * 1 = number of structures with non zero revent fields - */ -int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) -{ - int r; -#if defined(HAVE_POLL) && !defined(_POLL_EMUL_H_) - do { - r = poll(ufds, nfds, timeout_ms); - } while((r == -1) && (errno == EINTR)); -#elif defined(CURL_HAVE_WSAPOLL) - r = WSAPoll(ufds, nfds, timeout_ms); -#else - struct timeval timeout; - struct timeval *ptimeout; - fd_set fds_read; - fd_set fds_write; - fd_set fds_err; - curl_socket_t maxfd; - unsigned int i; - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_ZERO(&fds_err); - maxfd = (curl_socket_t)-1; - - for (i = 0; i < nfds; i++) { - if (ufds[i].fd == CURL_SOCKET_BAD) - continue; -#ifndef USE_WINSOCK /* winsock sockets are not in range [0..FD_SETSIZE] */ - if (ufds[i].fd >= FD_SETSIZE) { - errno = EINVAL; - return -1; - } -#endif - if (ufds[i].fd > maxfd) - maxfd = ufds[i].fd; - if (ufds[i].events & POLLIN) - FD_SET(ufds[i].fd, &fds_read); - if (ufds[i].events & POLLOUT) - FD_SET(ufds[i].fd, &fds_write); - if (ufds[i].events & POLLERR) - FD_SET(ufds[i].fd, &fds_err); - } - - if (timeout_ms < 0) { - ptimeout = NULL; /* wait forever */ - } else { - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - ptimeout = &timeout; - } - - do { - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); - } while((r == -1) && (Curl_sockerrno() == EINTR)); - - if (r < 0) - return -1; - if (r == 0) - return 0; - - r = 0; - for (i = 0; i < nfds; i++) { - ufds[i].revents = 0; - if (ufds[i].fd == CURL_SOCKET_BAD) - continue; - if (FD_ISSET(ufds[i].fd, &fds_read)) - ufds[i].revents |= POLLIN; - if (FD_ISSET(ufds[i].fd, &fds_write)) - ufds[i].revents |= POLLOUT; - if (FD_ISSET(ufds[i].fd, &fds_err)) - ufds[i].revents |= POLLERR; - if (ufds[i].revents != 0) - r++; - } -#endif - return r; -} - -#ifdef TPF -/* - * This is a replacement for select() on the TPF platform. - * It is used whenever libcurl calls select(). - * The call below to tpf_process_signals() is required because - * TPF's select calls are not signal interruptible. - * - * Return values are the same as select's. - */ -int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, - fd_set* excepts, struct timeval* tv) -{ - int rc; - - rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); - tpf_process_signals(); - return(rc); -} -#endif /* TPF */ diff --git a/Utilities/cmcurl/select.h b/Utilities/cmcurl/select.h deleted file mode 100644 index 7573b1f..0000000 --- a/Utilities/cmcurl/select.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __SELECT_H -#define __SELECT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifdef HAVE_SYS_POLL_H -#include -#else -#ifndef POLLIN -#define POLLIN 0x01 -#define POLLPRI 0x02 -#define POLLOUT 0x04 -#define POLLERR 0x08 -#define POLLHUP 0x10 -#define POLLNVAL 0x20 - -struct pollfd -{ - curl_socket_t fd; - short events; - short revents; -}; -#endif - -#endif - -#define CSELECT_IN 0x01 -#define CSELECT_OUT 0x02 -#define CSELECT_ERR 0x04 - -int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms); - -int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); - -#ifdef TPF -int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, - fd_set* excepts, struct timeval* tv); -#endif - -#endif diff --git a/Utilities/cmcurl/sendf.c b/Utilities/cmcurl/sendf.c deleted file mode 100644 index 500bf66..0000000 --- a/Utilities/cmcurl/sendf.c +++ /dev/null @@ -1,663 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include -#include -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include /* required for send() & recv() prototypes */ -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "connect.h" /* for the Curl_sockerrno() proto */ -#include "sslgen.h" -#include "ssh.h" -#include "multiif.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - -#ifdef HAVE_KRB4 -#include "krb4.h" -#else -#define Curl_sec_send(a,b,c,d) -1 -#define Curl_sec_read(a,b,c,d) -1 -#endif - -#include -#include "memory.h" -#include "strerror.h" -#include "easyif.h" /* for the Curl_convert_from_network prototype */ -/* The last #include file should be: */ -#include "memdebug.h" - -/* returns last node in linked list */ -static struct curl_slist *slist_get_last(struct curl_slist *list) -{ - struct curl_slist *item; - - /* if caller passed us a NULL, return now */ - if (!list) - return NULL; - - /* loop through to find the last item */ - item = list; - while (item->next) { - item = item->next; - } - return item; -} - -/* - * curl_slist_append() appends a string to the linked list. It always retunrs - * the address of the first record, so that you can sure this function as an - * initialization function as well as an append function. If you find this - * bothersome, then simply create a separate _init function and call it - * appropriately from within the proram. - */ -struct curl_slist *curl_slist_append(struct curl_slist *list, - const char *data) -{ - struct curl_slist *last; - struct curl_slist *new_item; - - new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist)); - if (new_item) { - char *dup = strdup(data); - if(dup) { - new_item->next = NULL; - new_item->data = dup; - } - else { - free(new_item); - return NULL; - } - } - else - return NULL; - - if (list) { - last = slist_get_last(list); - last->next = new_item; - return list; - } - - /* if this is the first item, then new_item *is* the list */ - return new_item; -} - -/* be nice and clean up resources */ -void curl_slist_free_all(struct curl_slist *list) -{ - struct curl_slist *next; - struct curl_slist *item; - - if (!list) - return; - - item = list; - do { - next = item->next; - - if (item->data) { - free(item->data); - } - free(item); - item = next; - } while (next); -} - -#ifdef CURL_DO_LINEEND_CONV -/* - * 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 SessionHandle *data, - char *startPtr, size_t size) -{ - char *inPtr, *outPtr; - - /* sanity check */ - if ((startPtr == NULL) || (size < 1)) { - return(size); - } - - if (data->state.prev_block_had_trailing_cr == TRUE) { - /* 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 */ - memcpy(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++; - inPtr++; - } - 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_infof() is for info message along the way */ - -void Curl_infof(struct SessionHandle *data, const char *fmt, ...) -{ - if(data && data->set.verbose) { - va_list ap; - size_t len; - char print_buffer[1024 + 1]; - va_start(ap, fmt); - vsnprintf(print_buffer, 1024, fmt, ap); - va_end(ap); - len = strlen(print_buffer); - Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL); - } -} - -/* Curl_failf() is for messages stating why we failed. - * The message SHALL NOT include any LF or CR. - */ - -void Curl_failf(struct SessionHandle *data, const char *fmt, ...) -{ - va_list ap; - size_t len; - va_start(ap, fmt); - - vsnprintf(data->state.buffer, BUFSIZE, fmt, ap); - - if(data->set.errorbuffer && !data->state.errorbuf) { - snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer); - data->state.errorbuf = TRUE; /* wrote error string */ - } - if(data->set.verbose) { - len = strlen(data->state.buffer); - if(len < BUFSIZE - 1) { - data->state.buffer[len] = '\n'; - data->state.buffer[++len] = '\0'; - } - Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL); - } - - va_end(ap); -} - -/* Curl_sendf() sends formated data to the server */ -CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, - const char *fmt, ...) -{ - struct SessionHandle *data = conn->data; - ssize_t bytes_written; - size_t write_len; - CURLcode res = CURLE_OK; - char *s; - char *sptr; - va_list ap; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* returns an allocated string */ - va_end(ap); - if(!s) - return CURLE_OUT_OF_MEMORY; /* failure */ - - bytes_written=0; - write_len = strlen(s); - sptr = s; - - while (1) { - /* Write the buffer to the socket */ - res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); - - if(CURLE_OK != res) - break; - - if(data->set.verbose) - Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn); - - if((size_t)bytes_written != write_len) { - /* if not all was written at once, we must advance the pointer, decrease - the size left and try again! */ - write_len -= bytes_written; - sptr += bytes_written; - } - else - break; - } - - free(s); /* free the output string */ - - return res; -} - -static ssize_t Curl_plain_send(struct connectdata *conn, - int num, - void *mem, - size_t len) -{ - curl_socket_t sockfd = conn->sock[num]; - ssize_t bytes_written = swrite(sockfd, mem, len); - - if(-1 == bytes_written) { - int err = Curl_sockerrno(); - - if( -#ifdef WSAEWOULDBLOCK - /* This is how Windows does it */ - (WSAEWOULDBLOCK == err) -#else - /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned - due to its inability to send off data without blocking. We therefor - treat both error codes the same here */ - (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) -#endif - ) - /* this is just a case of EWOULDBLOCK */ - bytes_written=0; - else - failf(conn->data, "Send failure: %s", - Curl_strerror(conn, err)); - } - return bytes_written; -} - -/* - * Curl_write() is an internal write function that sends data to the - * server. Works with plain sockets, SCP, SSL or kerberos. - */ -CURLcode Curl_write(struct connectdata *conn, - curl_socket_t sockfd, - void *mem, - size_t len, - ssize_t *written) -{ - ssize_t bytes_written; - CURLcode retcode; - int num = (sockfd == conn->sock[SECONDARYSOCKET]); - - if (conn->ssl[num].use) - /* only TRUE if SSL enabled */ - bytes_written = Curl_ssl_send(conn, num, mem, len); -#ifdef USE_LIBSSH2 - else if (conn->protocol & PROT_SCP) - bytes_written = Curl_scp_send(conn, num, mem, len); - else if (conn->protocol & PROT_SFTP) - bytes_written = Curl_sftp_send(conn, num, mem, len); -#endif /* !USE_LIBSSH2 */ - else if(conn->sec_complete) - /* only TRUE if krb4 enabled */ - bytes_written = Curl_sec_send(conn, num, mem, len); - else - bytes_written = Curl_plain_send(conn, num, mem, len); - - *written = bytes_written; - retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR; - - return retcode; -} - -/* 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. - */ -CURLcode Curl_client_write(struct connectdata *conn, - int type, - char *ptr, - size_t len) -{ - struct SessionHandle *data = conn->data; - size_t wrote; - - if (data->state.cancelled) { - /* We just suck everything into a black hole */ - return CURLE_OK; - } - - if(0 == len) - len = strlen(ptr); - - if(type & CLIENTWRITE_BODY) { - if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') { -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding */ - size_t rc; - rc = Curl_convert_from_network(data, ptr, len); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(rc != CURLE_OK) - return rc; -#endif /* CURL_DOES_CONVERSIONS */ - -#ifdef CURL_DO_LINEEND_CONV - /* convert end-of-line markers */ - len = convert_lineends(data, ptr, len); -#endif /* CURL_DO_LINEEND_CONV */ - } - /* If the previous block of data ended with CR and this block of data is - just a NL, then the length might be zero */ - if (len) { - wrote = data->set.fwrite(ptr, 1, len, data->set.out); - } - else { - wrote = len; - } - - if(wrote != len) { - failf (data, "Failed writing body"); - return CURLE_WRITE_ERROR; - } - } - - if((type & CLIENTWRITE_HEADER) && - (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). - */ - curl_write_callback writeit= - data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite; - - /* Note: The header is in the host encoding - regardless of the ftp transfer mode (ASCII/Image) */ - - wrote = writeit(ptr, 1, len, data->set.writeheader); - if(wrote != len) { - failf (data, "Failed writing header"); - return CURLE_WRITE_ERROR; - } - } - - return CURLE_OK; -} - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/* - * Internal read-from-socket function. This is meant to deal with plain - * sockets, SSL sockets and kerberos sockets. - * - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ -int Curl_read(struct connectdata *conn, /* connection data */ - 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 */ -{ - ssize_t nread; - size_t bytesfromsocket = 0; - char *buffertofill = NULL; - bool pipelining = (bool)(conn->data->multi && - Curl_multi_canPipeline(conn->data->multi)); - - /* 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 */ - - /* If session can pipeline, check connection buffer */ - if(pipelining) { - size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested); - - /* Copy from our master buffer first if we have some unread data there*/ - if (bytestocopy > 0) { - memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy); - conn->read_pos += bytestocopy; - conn->bits.stream_was_rewound = FALSE; - - *n = (ssize_t)bytestocopy; - return CURLE_OK; - } - /* If we come here, it means that there is no data to read from the buffer, - * so we read from the socket */ - bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer)); - buffertofill = conn->master_buffer; - } - else { - bytesfromsocket = MIN((long)sizerequested, conn->data->set.buffer_size ? - conn->data->set.buffer_size : BUFSIZE); - buffertofill = buf; - } - - if(conn->ssl[num].use) { - nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket); - - if(nread == -1) { - return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */ - } - } -#ifdef USE_LIBSSH2 - else if (conn->protocol & PROT_SCP) { - nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket); - /* TODO: return CURLE_OK also for nread <= 0 - read failures and timeouts ? */ - } - else if (conn->protocol & PROT_SFTP) { - nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket); - } -#endif /* !USE_LIBSSH2 */ - else { - if(conn->sec_complete) - nread = Curl_sec_read(conn, sockfd, buffertofill, - bytesfromsocket); - else - nread = sread(sockfd, buffertofill, bytesfromsocket); - - if(-1 == nread) { - int err = Curl_sockerrno(); -#ifdef USE_WINSOCK - if(WSAEWOULDBLOCK == err) -#else - if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)) -#endif - return -1; - } - } - - if (nread >= 0) { - if(pipelining) { - memcpy(buf, conn->master_buffer, nread); - conn->buf_len = nread; - conn->read_pos = nread; - } - - *n += nread; - } - - return CURLE_OK; -} - -/* return 0 on success */ -static int showit(struct SessionHandle *data, curl_infotype type, - char *ptr, size_t size) -{ - static const char * const s_infotype[CURLINFO_END] = { - "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; - -#ifdef CURL_DOES_CONVERSIONS - char buf[BUFSIZE+1]; - size_t conv_size = 0; - - switch(type) { - case CURLINFO_HEADER_OUT: - /* assume output headers are ASCII */ - /* copy the data into my buffer so the original is unchanged */ - if (size > BUFSIZE) { - size = BUFSIZE; /* truncate if necessary */ - buf[BUFSIZE] = '\0'; - } - conv_size = size; - memcpy(buf, ptr, size); - /* Special processing is needed for this block if it - * contains both headers and data (separated by CRLFCRLF). - * We want to convert just the headers, leaving the data as-is. - */ - if(size > 4) { - size_t i; - for(i = 0; i < size-4; i++) { - if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) { - /* convert everthing through this CRLFCRLF but no further */ - conv_size = i + 4; - break; - } - } - } - - Curl_convert_from_network(data, buf, conv_size); - /* Curl_convert_from_network calls failf if unsuccessful */ - /* we might as well continue even if it fails... */ - ptr = buf; /* switch pointer to use my buffer instead */ - break; - default: - /* leave everything else as-is */ - break; - } -#endif /* CURL_DOES_CONVERSIONS */ - - if(data->set.fdebug) - return (*data->set.fdebug)(data, type, ptr, size, - data->set.debugdata); - - switch(type) { - case CURLINFO_TEXT: - case CURLINFO_HEADER_OUT: - case CURLINFO_HEADER_IN: - fwrite(s_infotype[type], 2, 1, data->set.err); - fwrite(ptr, size, 1, data->set.err); -#ifdef CURL_DOES_CONVERSIONS - if(size != conv_size) { - /* we had untranslated data so we need an explicit newline */ - fwrite("\n", 1, 1, data->set.err); - } -#endif - break; - default: /* nada */ - break; - } - return 0; -} - -int Curl_debug(struct SessionHandle *data, curl_infotype type, - char *ptr, size_t size, - struct connectdata *conn) -{ - int rc; - if(data->set.printhost && conn && conn->host.dispname) { - char buffer[160]; - const char *t=NULL; - const char *w="Data"; - switch (type) { - case CURLINFO_HEADER_IN: - w = "Header"; - case CURLINFO_DATA_IN: - t = "from"; - break; - case CURLINFO_HEADER_OUT: - w = "Header"; - case CURLINFO_DATA_OUT: - t = "to"; - break; - default: - break; - } - - if(t) { - snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t, - conn->host.dispname); - rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer)); - if(rc) - return rc; - } - } - rc = showit(data, type, ptr, size); - return rc; -} diff --git a/Utilities/cmcurl/sendf.h b/Utilities/cmcurl/sendf.h deleted file mode 100644 index 7877df8..0000000 --- a/Utilities/cmcurl/sendf.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef __SENDF_H -#define __SENDF_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, - const char *fmt, ...); -void Curl_infof(struct SessionHandle *, const char *fmt, ...); -void Curl_failf(struct SessionHandle *, const char *fmt, ...); - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) -#if defined(__GNUC__) -/* This style of variable argument macros is a gcc extension */ -#define infof(x...) /*ignore*/ -#else -/* C99 compilers could use this if we could detect them */ -/*#define infof(...) */ -/* Cast the args to void to make them a noop, side effects notwithstanding */ -#define infof (void) -#endif -#else -#define infof Curl_infof -#endif -#define failf Curl_failf - -#define CLIENTWRITE_BODY 1 -#define CLIENTWRITE_HEADER 2 -#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) - -CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, - size_t len); - -void Curl_read_rewind(struct connectdata *conn, - size_t extraBytesRead); - -/* internal read-function, does plain socket, SSL and krb4 */ -int Curl_read(struct connectdata *conn, curl_socket_t sockfd, - char *buf, size_t buffersize, - ssize_t *n); -/* internal write-function, does plain socket, SSL and krb4 */ -CURLcode Curl_write(struct connectdata *conn, - curl_socket_t sockfd, - void *mem, size_t len, - ssize_t *written); - -/* the function used to output verbose information */ -int Curl_debug(struct SessionHandle *handle, curl_infotype type, - char *data, size_t size, - struct connectdata *conn); - - -#endif diff --git a/Utilities/cmcurl/setup.h b/Utilities/cmcurl/setup.h deleted file mode 100644 index 5ae881f..0000000 --- a/Utilities/cmcurl/setup.h +++ /dev/null @@ -1,390 +0,0 @@ -#ifndef __LIB_CURL_SETUP_H -#define __LIB_CURL_SETUP_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifdef HTTP_ONLY -#define CURL_DISABLE_TFTP -#define CURL_DISABLE_FTP -#define CURL_DISABLE_LDAP -#define CURL_DISABLE_TELNET -#define CURL_DISABLE_DICT -#define CURL_DISABLE_FILE -#endif /* HTTP_ONLY */ - -#if !defined(WIN32) && defined(__WIN32__) -/* Borland fix */ -#define WIN32 -#endif - -#if !defined(WIN32) && defined(_WIN32) -/* VS2005 on x64 fix */ -#define WIN32 -#endif - -#if defined(__clang__) -# pragma clang diagnostic ignored "-Wcast-align" -#endif - -/* - * Include configuration script results or hand-crafted - * configuration file for platforms which lack config tool. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#else - -/* -#ifdef _WIN32_WCE -#include "config-win32ce.h" -#else -#ifdef WIN32 -#include "config-win32.h" -#endif -#endif -*/ - -#ifdef macintosh -#include "config-mac.h" -#endif - -#ifdef AMIGA -#include "amigaos.h" -#endif - -#ifdef TPF -#include "config-tpf.h" /* hand-modified TPF config.h */ -/* change which select is used for libcurl */ -#define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e) -#endif - -#endif /* HAVE_CONFIG_H */ - -/* - * Include header files for windows builds before redefining anything. - * Use this preproessor block only to include or exclude windows.h, - * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs - * to any other further and independant block. Under Cygwin things work - * just as under linux (e.g. ) and the winsock headers should - * never be included when __CYGWIN__ is defined. configure script takes - * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, - * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. - */ - -#ifdef HAVE_WINDOWS_H -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# ifdef HAVE_WINSOCK2_H -# include -# ifdef HAVE_WS2TCPIP_H -# include -# endif -# else -# ifdef HAVE_WINSOCK_H -# include -# endif -# endif -#endif - -/* - * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else - * define USE_WINSOCK to 1 if we have and use WINSOCK API, else - * undefine USE_WINSOCK. - */ - -#undef USE_WINSOCK - -#ifdef HAVE_WINSOCK2_H -# define USE_WINSOCK 2 -#else -# ifdef HAVE_WINSOCK_H -# define USE_WINSOCK 1 -# endif -#endif - - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#if !defined(__cplusplus) && !defined(__BEOS__) && !defined(__ECOS) && !defined(typedef_bool) -typedef unsigned char bool; -#define typedef_bool -#endif - -#ifdef HAVE_LONGLONG -#define LONG_LONG long long -#define ENABLE_64BIT -#else -#ifdef _MSC_VER -#define LONG_LONG __int64 -#define ENABLE_64BIT -#endif /* _MSC_VER */ -#endif /* HAVE_LONGLONG */ - -#ifndef SIZEOF_CURL_OFF_T -/* If we don't know the size here, we assume a conservative size: 4. When - building libcurl, the actual size of this variable should be define in the - config*.h file. */ -#define SIZEOF_CURL_OFF_T 4 -#endif - -/* We set up our internal preferred (CURL_)FORMAT_OFF_T here */ -#if SIZEOF_CURL_OFF_T > 4 -#define FORMAT_OFF_T "lld" -#else -#define FORMAT_OFF_T "ld" -#endif /* SIZEOF_CURL_OFF_T */ - -#ifndef _REENTRANT -/* Solaris needs _REENTRANT set for a few function prototypes and things to - appear in the #include files. We need to #define it before all #include - files. Unixware needs it to build proper reentrant code. Others may also - need it. */ -#define _REENTRANT -#endif - -#include -#ifdef HAVE_ASSERT_H -#include -#endif -#include - -#ifdef __TANDEM /* for nsr-tandem-nsk systems */ -#include -#endif - -#ifndef STDC_HEADERS /* no standard C headers! */ -#include -#endif - -/* - * PellesC cludge section (yikes); - * - It has 'ssize_t', but it is in . The way the headers - * on Win32 are included, forces me to include this header here. - * - sys_nerr, EINTR is missing in v4.0 or older. - */ -#ifdef __POCC__ - #include - #include - #if (__POCC__ <= 400) - #define sys_nerr EILSEQ /* for strerror.c */ - #define EINTR -1 /* for select.c */ - #endif -#endif - -/* - * Salford-C cludge section (mostly borrowed from wxWidgets). - */ -#ifdef __SALFORDC__ - #pragma suppress 353 /* Possible nested comments */ - #pragma suppress 593 /* Define not used */ - #pragma suppress 61 /* enum has no name */ - #pragma suppress 106 /* unnamed, unused parameter */ - #include -#endif - -#if defined(CURLDEBUG) && defined(HAVE_ASSERT_H) -#define curlassert(x) assert(x) -#else -/* does nothing without CURLDEBUG defined */ -#define curlassert(x) -#endif - - -/* To make large file support transparent even on Windows */ -#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4) -#include /* must come first before we redefine stat() */ -#include -#define lseek(x,y,z) _lseeki64(x, y, z) -#define struct_stat struct _stati64 -#define stat(file,st) _stati64(file,st) -#define fstat(fd,st) _fstati64(fd,st) -#else -#define struct_stat struct stat -#endif /* Win32 with large file support */ - - -/* Below we define some functions. They should - 1. close a socket - - 4. set the SIGALRM signal timeout - 5. set dir/file naming defines - */ - -#ifdef WIN32 - -#if !defined(__CYGWIN__) -#define sclose(x) closesocket(x) - -#undef HAVE_ALARM -#else - /* gcc-for-win is still good :) */ -#define sclose(x) close(x) -#define HAVE_ALARM -#endif /* !GNU or mingw */ - -#define DIR_CHAR "\\" -#define DOT_CHAR "_" - -#else /* WIN32 */ - -#ifdef MSDOS /* Watt-32 */ -#include -#define sclose(x) close_s(x) -#define select(n,r,w,x,t) select_s(n,r,w,x,t) -#define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) -#define IOCTL_3_ARGS -#include -#ifdef word -#undef word -#endif - -#else /* MSDOS */ - -#ifdef __VMS -#define IOCTL_3_ARGS 1 -#endif - -#ifdef __BEOS__ -#define sclose(x) closesocket(x) -#else /* __BEOS__ */ -#define sclose(x) close(x) -#endif /* __BEOS__ */ - -#define HAVE_ALARM - -#endif /* MSDOS */ - -#ifdef _AMIGASF -#undef HAVE_ALARM -#undef sclose -#define sclose(x) CloseSocket(x) -#endif - -#define DIR_CHAR "/" -#ifndef DOT_CHAR -#define DOT_CHAR "." -#endif - -#ifdef MSDOS -#undef DOT_CHAR -#define DOT_CHAR "_" -#endif - -#ifndef fileno /* sunos 4 have this as a macro! */ -int fileno( FILE *stream); -#endif - -#endif /* WIN32 */ - -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \ - !defined(__LCC__) /* lcc-win32 doesn't have _beginthreadex() */ -#ifdef ENABLE_IPV6 -#define USE_THREADING_GETADDRINFO -#else -#define USE_THREADING_GETHOSTBYNAME /* Cygwin uses alarm() function */ -#endif -#endif - -/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where - _beginthreadex() is not available */ -#if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES) -#undef USE_THREADING_GETADDRINFO -#undef USE_THREADING_GETHOSTBYNAME -#define CURL_NO__BEGINTHREADEX -#endif - -/* - * msvc 6.0 does not have struct sockaddr_storage and - * does not define IPPROTO_ESP in winsock2.h. But both - * are available if PSDK is properly installed. - */ - -#ifdef _MSC_VER -#if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP)) -#undef HAVE_STRUCT_SOCKADDR_STORAGE -#endif -#endif - -#ifdef mpeix -#define IOCTL_3_ARGS -#endif - -#ifdef NETWARE -#undef HAVE_ALARM -#endif - -#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H) -/* The lib was present and the tld.h header (which is missing in libidn 0.3.X - but we only work with libidn 0.4.1 or later) */ -#define USE_LIBIDN -#endif - -#ifndef SIZEOF_TIME_T -/* assume default size of time_t to be 32 bit */ -#define SIZEOF_TIME_T 4 -#endif - -#define LIBIDN_REQUIRED_VERSION "0.4.1" - -#ifdef __UCLIBC__ -#define HAVE_INET_NTOA_R_2_ARGS 1 -#endif - -#if defined(USE_GNUTLS) || defined(USE_SSLEAY) -#define USE_SSL /* Either OpenSSL || GnuTLS */ -#endif - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM) -#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) -#define USE_NTLM -#endif -#endif - -#ifdef CURLDEBUG -#define DEBUGF(x) x -#else -#define DEBUGF(x) -#endif - -/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */ -#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE) -#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") -#endif - -/* - * Include macros and defines that should only be processed once. - */ - -#ifndef __SETUP_ONCE_H -#include "setup_once.h" -#endif - -#endif /* __LIB_CURL_SETUP_H */ diff --git a/Utilities/cmcurl/setup_once.h b/Utilities/cmcurl/setup_once.h deleted file mode 100644 index ee68641..0000000 --- a/Utilities/cmcurl/setup_once.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef __SETUP_ONCE_H -#define __SETUP_ONCE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - - -/******************************************************************** - * NOTICE * - * ======== * - * * - * Content of header files lib/setup_once.h and ares/setup_once.h * - * must be kept in sync. Modify the other one if you change this. * - * * - ********************************************************************/ - - -/* - * If we have the MSG_NOSIGNAL define, make sure we use - * it as the fourth argument of function send() - */ - -#ifdef HAVE_MSG_NOSIGNAL -#define SEND_4TH_ARG MSG_NOSIGNAL -#else -#define SEND_4TH_ARG 0 -#endif - - -/* - * The definitions for the return type and arguments types - * of functions recv() and send() belong and come from the - * configuration file. Do not define them in any other place. - * - * 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 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 - * be defined. - * - * 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 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 - * SEND_TYPE_RETV must also be defined. - */ - -#ifdef HAVE_RECV -#if !defined(RECV_TYPE_ARG1) || \ - !defined(RECV_TYPE_ARG2) || \ - !defined(RECV_TYPE_ARG3) || \ - !defined(RECV_TYPE_ARG4) || \ - !defined(RECV_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recv - /* */ -#else -#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ - (RECV_TYPE_ARG2)(y), \ - (RECV_TYPE_ARG3)(z), \ - (RECV_TYPE_ARG4)(0)) -#endif -#else /* HAVE_RECV */ -#ifndef sread - /* */ - Error Missing_definition_of_macro_sread - /* */ -#endif -#endif /* HAVE_RECV */ - -#ifdef HAVE_SEND -#if !defined(SEND_TYPE_ARG1) || \ - !defined(SEND_QUAL_ARG2) || \ - !defined(SEND_TYPE_ARG2) || \ - !defined(SEND_TYPE_ARG3) || \ - !defined(SEND_TYPE_ARG4) || \ - !defined(SEND_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_send - /* */ -#else -#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ - (SEND_TYPE_ARG2)(y), \ - (SEND_TYPE_ARG3)(z), \ - (SEND_TYPE_ARG4)(SEND_4TH_ARG)) -#endif -#else /* HAVE_SEND */ -#ifndef swrite - /* */ - Error Missing_definition_of_macro_swrite - /* */ -#endif -#endif /* HAVE_SEND */ - - -/* - * Uppercase macro versions of ANSI/ISO is*() functions/macros which - * avoid negative number inputs with argument byte codes > 127. - */ - -#define ISSPACE(x) (isspace((int) ((unsigned char)x))) -#define ISDIGIT(x) (isdigit((int) ((unsigned char)x))) -#define ISALNUM(x) (isalnum((int) ((unsigned char)x))) -#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) -#define ISGRAPH(x) (isgraph((int) ((unsigned char)x))) -#define ISALPHA(x) (isalpha((int) ((unsigned char)x))) -#define ISPRINT(x) (isprint((int) ((unsigned char)x))) - - -/* - * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. - */ - -#ifndef HAVE_SIG_ATOMIC_T -typedef int sig_atomic_t; -#define HAVE_SIG_ATOMIC_T -#endif - - -/* - * Default return type for signal handlers. - */ - -#ifndef RETSIGTYPE -#define RETSIGTYPE void -#endif - - -#endif /* __SETUP_ONCE_H */ - diff --git a/Utilities/cmcurl/share.c b/Utilities/cmcurl/share.c deleted file mode 100644 index de13b60..0000000 --- a/Utilities/cmcurl/share.c +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include -#include -#include -#include -#include "urldata.h" -#include "share.h" -#include "memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -CURLSH * -curl_share_init(void) -{ - struct Curl_share *share = - (struct Curl_share *)malloc(sizeof(struct Curl_share)); - if (share) { - memset (share, 0, sizeof(struct Curl_share)); - share->specifier |= (1<dirty) - /* don't allow setting options while one or more handles are already - using this share */ - return CURLSHE_IN_USE; - - va_start(param, option); - - switch(option) { - case CURLSHOPT_SHARE: - /* this is a type this share will share */ - type = va_arg(param, int); - share->specifier |= (1<hostcache) { - share->hostcache = Curl_mk_dnscache(); - if(!share->hostcache) - return CURLSHE_NOMEM; - } - break; - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - case CURL_LOCK_DATA_COOKIE: - if (!share->cookies) { - share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE ); - if(!share->cookies) - return CURLSHE_NOMEM; - } - break; -#endif /* CURL_DISABLE_HTTP */ - - case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */ - case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ - - default: - return CURLSHE_BAD_OPTION; - } - break; - - case CURLSHOPT_UNSHARE: - /* this is a type this share will no longer share */ - type = va_arg(param, int); - share->specifier &= ~(1<hostcache) { - Curl_hash_destroy(share->hostcache); - share->hostcache = NULL; - } - break; - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - case CURL_LOCK_DATA_COOKIE: - if (share->cookies) { - Curl_cookie_cleanup(share->cookies); - share->cookies = NULL; - } - break; -#endif /* CURL_DISABLE_HTTP */ - - case CURL_LOCK_DATA_SSL_SESSION: - break; - - case CURL_LOCK_DATA_CONNECT: - break; - - default: - return CURLSHE_BAD_OPTION; - } - break; - - case CURLSHOPT_LOCKFUNC: - lockfunc = va_arg(param, curl_lock_function); - share->lockfunc = lockfunc; - break; - - case CURLSHOPT_UNLOCKFUNC: - unlockfunc = va_arg(param, curl_unlock_function); - share->unlockfunc = unlockfunc; - break; - - case CURLSHOPT_USERDATA: - ptr = va_arg(param, void *); - share->clientdata = ptr; - break; - - default: - return CURLSHE_BAD_OPTION; - } - - return CURLSHE_OK; -} - -CURLSHcode -curl_share_cleanup(CURLSH *sh) -{ - struct Curl_share *share = (struct Curl_share *)sh; - - if (share == NULL) - return CURLSHE_INVALID; - - if(share->lockfunc) - share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE, - share->clientdata); - - if (share->dirty) { - if(share->unlockfunc) - share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); - return CURLSHE_IN_USE; - } - - if(share->hostcache) - Curl_hash_destroy(share->hostcache); - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(share->cookies) - Curl_cookie_cleanup(share->cookies); -#endif /* CURL_DISABLE_HTTP */ - - if(share->unlockfunc) - share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); - free(share); - - return CURLSHE_OK; -} - - -CURLSHcode -Curl_share_lock(struct SessionHandle *data, curl_lock_data type, - curl_lock_access accesstype) -{ - struct Curl_share *share = data->share; - - if (share == NULL) - return CURLSHE_INVALID; - - if(share->specifier & (1<lockfunc) /* only call this if set! */ - share->lockfunc(data, type, accesstype, share->clientdata); - } - /* else if we don't share this, pretend successful lock */ - - return CURLSHE_OK; -} - -CURLSHcode -Curl_share_unlock(struct SessionHandle *data, curl_lock_data type) -{ - struct Curl_share *share = data->share; - - if (share == NULL) - return CURLSHE_INVALID; - - if(share->specifier & (1<unlockfunc) /* only call this if set! */ - share->unlockfunc (data, type, share->clientdata); - } - - return CURLSHE_OK; -} diff --git a/Utilities/cmcurl/share.h b/Utilities/cmcurl/share.h deleted file mode 100644 index 5cfe8c7..0000000 --- a/Utilities/cmcurl/share.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __CURL_SHARE_H -#define __CURL_SHARE_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include -#include "cookie.h" - -/* SalfordC says "A structure member may not be volatile". Hence: - */ -#ifdef __SALFORDC__ -#define CURL_VOLATILE -#else -#define CURL_VOLATILE volatile -#endif - -/* this struct is libcurl-private, don't export details */ -struct Curl_share { - unsigned int specifier; - CURL_VOLATILE unsigned int dirty; - - curl_lock_function lockfunc; - curl_unlock_function unlockfunc; - void *clientdata; - - struct curl_hash *hostcache; - struct CookieInfo *cookies; -}; - -CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, - curl_lock_access); -CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data); - -#endif /* __CURL_SHARE_H */ diff --git a/Utilities/cmcurl/sockaddr.h b/Utilities/cmcurl/sockaddr.h deleted file mode 100644 index 78dad4d..0000000 --- a/Utilities/cmcurl/sockaddr.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __SOCKADDR_H -#define __SOCKADDR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE -struct Curl_sockaddr_storage { - struct sockaddr_storage buffer; -}; -#else -struct Curl_sockaddr_storage { - char buffer[256]; /* this should be big enough to fit a lot */ -}; -#endif - -#endif /* __SOCKADDR_H */ diff --git a/Utilities/cmcurl/socks.c b/Utilities/cmcurl/socks.c deleted file mode 100644 index e0e947b..0000000 --- a/Utilities/cmcurl/socks.c +++ /dev/null @@ -1,592 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef NEED_MALLOC_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "strequal.h" -#include "select.h" -#include "connect.h" -#include "timeval.h" -#include "socks.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * Helper read-from-socket functions. Does the same as Curl_read() but it - * blocks until all bytes amount of buffersize will be read. No more, no less. - * - * This is STUPID BLOCKING behaviour which we frown upon, but right now this - * is what we have... - */ -static int blockread_all(struct connectdata *conn, /* connection data */ - curl_socket_t sockfd, /* read from this socket */ - char *buf, /* store read data here */ - ssize_t buffersize, /* max amount to read */ - ssize_t *n, /* amount bytes read */ - long conn_timeout) /* timeout for data wait - relative to - conn->created */ -{ - ssize_t nread; - ssize_t allread = 0; - int result; - struct timeval tvnow; - long conntime; - *n = 0; - do { - tvnow = Curl_tvnow(); - /* calculating how long connection is establishing */ - conntime = Curl_tvdiff(tvnow, conn->created); - if(conntime > conn_timeout) { - /* we already got the timeout */ - result = ~CURLE_OK; - break; - } - if(Curl_select(sockfd, CURL_SOCKET_BAD, - (int)(conn_timeout - conntime)) <= 0) { - result = ~CURLE_OK; - break; - } - result = Curl_read(conn, sockfd, buf, buffersize, &nread); - if(result) - break; - - if(buffersize == nread) { - allread += nread; - *n = allread; - result = CURLE_OK; - break; - } - buffersize -= nread; - buf += nread; - allread += nread; - } while(1); - return result; -} - -/* -* This function logs in to a SOCKS4 proxy and sends the specifics to the final -* destination server. -* -* Reference : -* http://socks.permeo.com/protocol/socks4.protocol -* -* Note : -* Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" -* Nonsupport "Identification Protocol (RFC1413)" -*/ -CURLcode Curl_SOCKS4(const char *proxy_name, - struct connectdata *conn) -{ - unsigned char socksreq[262]; /* room for SOCKS4 request incl. user id */ - int result; - CURLcode code; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - long timeout; - struct SessionHandle *data = conn->data; - - /* get timeout */ - if(data->set.timeout && data->set.connecttimeout) { - if (data->set.timeout < data->set.connecttimeout) - timeout = data->set.timeout*1000; - else - timeout = data->set.connecttimeout*1000; - } - else if(data->set.timeout) - timeout = data->set.timeout*1000; - else if(data->set.connecttimeout) - timeout = data->set.connecttimeout*1000; - else - timeout = DEFAULT_CONNECT_TIMEOUT; - - Curl_nonblock(sock, FALSE); - - /* - * Compose socks4 request - * - * Request format - * - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * | VN | CD | DSTPORT | DSTIP | USERID |NULL| - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * # of bytes: 1 1 2 4 variable 1 - */ - - socksreq[0] = 4; /* version (SOCKS4) */ - socksreq[1] = 1; /* connect */ - *((unsigned short*)&socksreq[2]) = htons(conn->remote_port); - - /* DNS resolve */ - { - struct Curl_dns_entry *dns; - Curl_addrinfo *hp=NULL; - int rc; - - rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns); - - if(rc == CURLRESOLV_ERROR) - return CURLE_COULDNT_RESOLVE_PROXY; - - if(rc == CURLRESOLV_PENDING) - /* this requires that we're in "wait for resolve" state */ - rc = Curl_wait_for_resolv(conn, &dns); - - /* - * 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) - hp=dns->addr; - if (hp) { - char buf[64]; - unsigned short ip[4]; - Curl_printable_address(hp, buf, sizeof(buf)); - - if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - /* Set DSTIP */ - socksreq[4] = (unsigned char)ip[0]; - socksreq[5] = (unsigned char)ip[1]; - socksreq[6] = (unsigned char)ip[2]; - socksreq[7] = (unsigned char)ip[3]; - } - else - hp = NULL; /* fail! */ - - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - - } - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", - conn->host.name); - return CURLE_COULDNT_RESOLVE_HOST; - } - } - - /* - * This is currently not supporting "Identification Protocol (RFC1413)". - */ - socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ - if(proxy_name) { - size_t plen = strlen(proxy_name); - if(plen >= sizeof(socksreq) - 8) { - failf(data, "Too long SOCKS proxy name, can't use!\n"); - return CURLE_COULDNT_CONNECT; - } - /* copy the proxy name WITH trailing zero */ - memcpy(socksreq + 8, proxy_name, plen+1); - } - - /* - * Make connection - */ - { - ssize_t actualread; - ssize_t written; - int packetsize = 9 + - (int)strlen((char*)socksreq + 8); /* size including NUL */ - - /* Send request */ - code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); - if ((code != CURLE_OK) || (written != packetsize)) { - failf(data, "Failed to send SOCKS4 connect request."); - return CURLE_COULDNT_CONNECT; - } - - packetsize = 8; /* receive data size */ - - /* Receive response */ - result = blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); - if ((result != CURLE_OK) || (actualread != packetsize)) { - failf(data, "Failed to receive SOCKS4 connect request ack."); - return CURLE_COULDNT_CONNECT; - } - - /* - * Response format - * - * +----+----+----+----+----+----+----+----+ - * | VN | CD | DSTPORT | DSTIP | - * +----+----+----+----+----+----+----+----+ - * # of bytes: 1 1 2 4 - * - * VN is the version of the reply code and should be 0. CD is the result - * code with one of the following values: - * - * 90: request granted - * 91: request rejected or failed - * 92: request rejected because SOCKS server cannot connect to - * identd on the client - * 93: request rejected because the client program and identd - * report different user-ids - */ - - /* wrong version ? */ - if (socksreq[0] != 0) { - failf(data, - "SOCKS4 reply has wrong version, version should be 4."); - return CURLE_COULDNT_CONNECT; - } - - /* Result */ - switch(socksreq[1]) - { - case 90: - infof(data, "SOCKS4 request granted.\n"); - break; - case 91: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected or failed.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); - return CURLE_COULDNT_CONNECT; - case 92: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected because SOCKS server cannot connect to " - "identd on the client.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); - return CURLE_COULDNT_CONNECT; - case 93: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", request rejected because the client program and identd " - "report different user-ids.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); - return CURLE_COULDNT_CONNECT; - default: - failf(data, - "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" - ", Unknown.", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); - return CURLE_COULDNT_CONNECT; - } - } - - Curl_nonblock(sock, TRUE); - - return CURLE_OK; /* Proxy was successful! */ -} - -/* - * This function logs in to a SOCKS5 proxy and sends the specifics to the final - * destination server. - */ -CURLcode Curl_SOCKS5(const char *proxy_name, - const char *proxy_password, - struct connectdata *conn) -{ - /* - According to the RFC1928, section "6. Replies". This is what a SOCK5 - replies: - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ - - Where: - - o VER protocol version: X'05' - o REP Reply field: - o X'00' succeeded - */ - - unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ - ssize_t actualread; - ssize_t written; - int result; - CURLcode code; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data = conn->data; - long timeout; - - /* get timeout */ - if(data->set.timeout && data->set.connecttimeout) { - if (data->set.timeout < data->set.connecttimeout) - timeout = data->set.timeout*1000; - else - timeout = data->set.connecttimeout*1000; - } - else if(data->set.timeout) - timeout = data->set.timeout*1000; - else if(data->set.connecttimeout) - timeout = data->set.connecttimeout*1000; - else - timeout = DEFAULT_CONNECT_TIMEOUT; - - Curl_nonblock(sock, TRUE); - - /* wait until socket gets connected */ - result = Curl_select(CURL_SOCKET_BAD, sock, (int)timeout); - - if(-1 == result) { - failf(conn->data, "SOCKS5: no connection here"); - return CURLE_COULDNT_CONNECT; - } - else if(0 == result) { - failf(conn->data, "SOCKS5: connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(result & CSELECT_ERR) { - failf(conn->data, "SOCKS5: error occured during connection"); - return CURLE_COULDNT_CONNECT; - } - - socksreq[0] = 5; /* version */ - socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */ - socksreq[2] = 0; /* no authentication */ - socksreq[3] = 2; /* username/password */ - - Curl_nonblock(sock, FALSE); - - code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), - &written); - if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) { - failf(data, "Unable to send initial SOCKS5 request."); - return CURLE_COULDNT_CONNECT; - } - - Curl_nonblock(sock, TRUE); - - result = Curl_select(sock, CURL_SOCKET_BAD, (int)timeout); - - if(-1 == result) { - failf(conn->data, "SOCKS5 nothing to read"); - return CURLE_COULDNT_CONNECT; - } - else if(0 == result) { - failf(conn->data, "SOCKS5 read timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - if(result & CSELECT_ERR) { - failf(conn->data, "SOCKS5 read error occured"); - return CURLE_RECV_ERROR; - } - - Curl_nonblock(sock, FALSE); - - result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, timeout); - if ((result != CURLE_OK) || (actualread != 2)) { - failf(data, "Unable to receive initial SOCKS5 response."); - return CURLE_COULDNT_CONNECT; - } - - if (socksreq[0] != 5) { - failf(data, "Received invalid version in initial SOCKS5 response."); - return CURLE_COULDNT_CONNECT; - } - if (socksreq[1] == 0) { - /* Nothing to do, no authentication needed */ - ; - } - else if (socksreq[1] == 2) { - /* Needs user name and password */ - size_t userlen, pwlen; - int len; - if(proxy_name && proxy_password) { - userlen = strlen(proxy_name); - pwlen = proxy_password?strlen(proxy_password):0; - } - else { - userlen = 0; - pwlen = 0; - } - - /* username/password request looks like - * +----+------+----------+------+----------+ - * |VER | ULEN | UNAME | PLEN | PASSWD | - * +----+------+----------+------+----------+ - * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | - * +----+------+----------+------+----------+ - */ - len = 0; - socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (char) userlen; - memcpy(socksreq + len, proxy_name, (int) userlen); - len += userlen; - socksreq[len++] = (char) pwlen; - memcpy(socksreq + len, proxy_password, (int) pwlen); - len += pwlen; - - code = Curl_write(conn, sock, (char *)socksreq, len, &written); - if ((code != CURLE_OK) || (len != written)) { - failf(data, "Failed to send SOCKS5 sub-negotiation request."); - return CURLE_COULDNT_CONNECT; - } - - result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); - if ((result != CURLE_OK) || (actualread != 2)) { - failf(data, "Unable to receive SOCKS5 sub-negotiation response."); - return CURLE_COULDNT_CONNECT; - } - - /* ignore the first (VER) byte */ - if (socksreq[1] != 0) { /* status */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); - return CURLE_COULDNT_CONNECT; - } - - /* Everything is good so far, user was authenticated! */ - } - else { - /* error */ - if (socksreq[1] == 1) { - failf(data, - "SOCKS5 GSSAPI per-message authentication is not supported."); - return CURLE_COULDNT_CONNECT; - } - else if (socksreq[1] == 255) { - if (!proxy_name || !*proxy_name) { - failf(data, - "No authentication method was acceptable. (It is quite likely" - " that the SOCKS5 server wanted a username/password, since none" - " was supplied to the server on this connection.)"); - } - else { - failf(data, "No authentication method was acceptable."); - } - return CURLE_COULDNT_CONNECT; - } - else { - failf(data, - "Undocumented SOCKS5 mode attempted to be used by server."); - return CURLE_COULDNT_CONNECT; - } - } - - /* Authentication is complete, now specify destination to the proxy */ - socksreq[0] = 5; /* version (SOCKS5) */ - socksreq[1] = 1; /* connect */ - socksreq[2] = 0; /* must be zero */ - socksreq[3] = 1; /* IPv4 = 1 */ - - { - struct Curl_dns_entry *dns; - Curl_addrinfo *hp=NULL; - int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns); - - if(rc == CURLRESOLV_ERROR) - return CURLE_COULDNT_RESOLVE_HOST; - - if(rc == CURLRESOLV_PENDING) - /* this requires that we're in "wait for resolve" state */ - rc = Curl_wait_for_resolv(conn, &dns); - - /* - * 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) - hp=dns->addr; - if (hp) { - char buf[64]; - unsigned short ip[4]; - Curl_printable_address(hp, buf, sizeof(buf)); - - if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - socksreq[4] = (unsigned char)ip[0]; - socksreq[5] = (unsigned char)ip[1]; - socksreq[6] = (unsigned char)ip[2]; - socksreq[7] = (unsigned char)ip[3]; - } - else - hp = NULL; /* fail! */ - - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - } - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", - conn->host.name); - return CURLE_COULDNT_RESOLVE_HOST; - } - } - - *((unsigned short*)&socksreq[8]) = htons(conn->remote_port); - - { - const int packetsize = 10; - - code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); - if ((code != CURLE_OK) || (written != packetsize)) { - failf(data, "Failed to send SOCKS5 connect request."); - return CURLE_COULDNT_CONNECT; - } - - result = blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); - if ((result != CURLE_OK) || (actualread != packetsize)) { - failf(data, "Failed to receive SOCKS5 connect request ack."); - return CURLE_COULDNT_CONNECT; - } - - if (socksreq[0] != 5) { /* version */ - failf(data, - "SOCKS5 reply has wrong version, version should be 5."); - return CURLE_COULDNT_CONNECT; - } - if (socksreq[1] != 0) { /* Anything besides 0 is an error */ - failf(data, - "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); - return CURLE_COULDNT_CONNECT; - } - } - - Curl_nonblock(sock, TRUE); - return CURLE_OK; /* Proxy was successful! */ -} diff --git a/Utilities/cmcurl/socks.h b/Utilities/cmcurl/socks.h deleted file mode 100644 index 0da9879..0000000 --- a/Utilities/cmcurl/socks.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __SOCKS_H -#define __SOCKS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * This function logs in to a SOCKS4 proxy and sends the specifics to the - * final destination server. - */ -CURLcode Curl_SOCKS4(const char *proxy_name, - struct connectdata *conn); - -/* - * This function logs in to a SOCKS5 proxy and sends the specifics to the - * final destination server. - */ -CURLcode Curl_SOCKS5(const char *proxy_name, - const char *proxy_password, - struct connectdata *conn); - -#endif diff --git a/Utilities/cmcurl/speedcheck.c b/Utilities/cmcurl/speedcheck.c deleted file mode 100644 index adda8a9..0000000 --- a/Utilities/cmcurl/speedcheck.c +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#include -#include "urldata.h" -#include "sendf.h" -#include "multiif.h" -#include "speedcheck.h" - -void Curl_speedinit(struct SessionHandle *data) -{ - memset(&data->state.keeps_speed, 0, sizeof(struct timeval)); -} - -CURLcode Curl_speedcheck(struct SessionHandle *data, - struct timeval now) -{ - if((data->progress.current_speed >= 0) && - data->set.low_speed_time && - (Curl_tvlong(data->state.keeps_speed) != 0) && - (data->progress.current_speed < data->set.low_speed_limit)) { - long howlong = Curl_tvdiff(now, data->state.keeps_speed); - - /* We are now below the "low speed limit". If we are below it - for "low speed time" seconds we consider that enough reason - to abort the download. */ - - if( (howlong/1000) > data->set.low_speed_time) { - /* we have been this slow for long enough, now die */ - failf(data, - "Operation too slow. " - "Less than %d bytes/sec transfered the last %d seconds", - data->set.low_speed_limit, - data->set.low_speed_time); - return CURLE_OPERATION_TIMEOUTED; - } - Curl_expire(data, howlong); - } - else { - /* we keep up the required speed all right */ - data->state.keeps_speed = now; - - if(data->set.low_speed_limit) - /* if there is a low speed limit enabled, we set the expire timer to - make this connection's speed get checked again no later than when - this time is up */ - Curl_expire(data, data->set.low_speed_time*1000); - } - return CURLE_OK; -} diff --git a/Utilities/cmcurl/speedcheck.h b/Utilities/cmcurl/speedcheck.h deleted file mode 100644 index 62475f6..0000000 --- a/Utilities/cmcurl/speedcheck.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __SPEEDCHECK_H -#define __SPEEDCHECK_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include "timeval.h" - -void Curl_speedinit(struct SessionHandle *data); -CURLcode Curl_speedcheck(struct SessionHandle *data, - struct timeval now); - -#endif diff --git a/Utilities/cmcurl/splay.c b/Utilities/cmcurl/splay.c deleted file mode 100644 index 9fb66c7..0000000 --- a/Utilities/cmcurl/splay.c +++ /dev/null @@ -1,425 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1997 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include -#include - -#include "splay.h" - -#define compare(i,j) ((i)-(j)) - -/* Set this to a key value that will *NEVER* appear otherwise */ -#define KEY_NOTUSED -1 - -/* - * Splay using the key i (which may or may not be in the tree.) The starting - * root is t. - */ -struct Curl_tree *Curl_splay(int i, struct Curl_tree *t) -{ - struct Curl_tree N, *l, *r, *y; - int comp; - - if (t == NULL) - return t; - N.smaller = N.larger = NULL; - l = r = &N; - - for (;;) { - comp = compare(i, t->key); - if (comp < 0) { - if (t->smaller == NULL) - break; - if (compare(i, t->smaller->key) < 0) { - y = t->smaller; /* rotate smaller */ - t->smaller = y->larger; - y->larger = t; - t = y; - if (t->smaller == NULL) - break; - } - r->smaller = t; /* link smaller */ - r = t; - t = t->smaller; - } - else if (comp > 0) { - if (t->larger == NULL) - break; - if (compare(i, t->larger->key) > 0) { - y = t->larger; /* rotate larger */ - t->larger = y->smaller; - y->smaller = t; - t = y; - if (t->larger == NULL) - break; - } - l->larger = t; /* link larger */ - l = t; - t = t->larger; - } - else - break; - } - - l->larger = t->smaller; /* assemble */ - r->smaller = t->larger; - t->smaller = N.larger; - t->larger = N.smaller; - - return t; -} - -/* Insert key i into the tree t. Return a pointer to the resulting tree or - NULL if something went wrong. */ -struct Curl_tree *Curl_splayinsert(int i, - struct Curl_tree *t, - struct Curl_tree *node) -{ - if (node == NULL) - return t; - - if (t != NULL) { - t = Curl_splay(i,t); - if (compare(i, t->key)==0) { - /* There already exists a node in the tree with the very same key. Build - a linked list of nodes. We make the new 'node' struct the new master - node and make the previous node the first one in the 'same' list. */ - - node->same = t; - node->key = i; - node->smaller = t->smaller; - node->larger = t->larger; - - t->smaller = node; /* in the sub node for this same key, we use the - smaller pointer to point back to the master - node */ - - t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED - to quickly identify this node as a subnode */ - - return node; /* new root node */ - } - } - - if (t == NULL) { - node->smaller = node->larger = NULL; - } - else if (compare(i, t->key) < 0) { - node->smaller = t->smaller; - node->larger = t; - t->smaller = NULL; - - } - else { - node->larger = t->larger; - node->smaller = t; - t->larger = NULL; - } - node->key = i; - - node->same = NULL; /* no identical node (yet) */ - return node; -} - -#if 0 -/* Deletes 'i' from the tree if it's there (with an exact match). Returns a - pointer to the resulting tree. - - Function not used in libcurl. -*/ -struct Curl_tree *Curl_splayremove(int i, struct Curl_tree *t, - struct Curl_tree **removed) -{ - struct Curl_tree *x; - - *removed = NULL; /* default to no removed */ - - if (t==NULL) - return NULL; - - t = Curl_splay(i,t); - if (compare(i, t->key) == 0) { /* found it */ - - /* FIRST! Check if there is a list with identical sizes */ - if((x = t->same)) { - /* there is, pick one from the list */ - - /* 'x' is the new root node */ - - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - - *removed = t; - return x; /* new root */ - } - - if (t->smaller == NULL) { - x = t->larger; - } - else { - x = Curl_splay(i, t->smaller); - x->larger = t->larger; - } - *removed = t; - - return x; - } - else - return t; /* It wasn't there */ -} -#endif - -/* Finds and deletes the best-fit node from the tree. Return a pointer to the - resulting tree. best-fit means the node with the given or lower number */ -struct Curl_tree *Curl_splaygetbest(int i, struct Curl_tree *t, - struct Curl_tree **removed) -{ - struct Curl_tree *x; - - if (!t) { - *removed = NULL; /* none removed since there was no root */ - return NULL; - } - - t = Curl_splay(i,t); - if(compare(i, t->key) < 0) { - /* too big node, try the smaller chain */ - if(t->smaller) - t=Curl_splay(t->smaller->key, t); - else { - /* fail */ - *removed = NULL; - return t; - } - } - - if (compare(i, t->key) >= 0) { /* found it */ - /* FIRST! Check if there is a list with identical sizes */ - x = t->same; - if(x) { - /* there is, pick one from the list */ - - /* 'x' is the new root node */ - - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - - *removed = t; - return x; /* new root */ - } - - if (t->smaller == NULL) { - x = t->larger; - } - else { - x = Curl_splay(i, t->smaller); - x->larger = t->larger; - } - *removed = t; - - return x; - } - else { - *removed = NULL; /* no match */ - return t; /* It wasn't there */ - } -} - - -/* 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! TODO: document error codes. - When returning error, it does not touch the 'newroot' pointer. - - NOTE: when the last node of the tree is removed, there's no tree left so - 'newroot' will be made to point to NULL. -*/ -int Curl_splayremovebyaddr(struct Curl_tree *t, - struct Curl_tree *remove, - struct Curl_tree **newroot) -{ - struct Curl_tree *x; - - if (!t || !remove) - return 1; - - if(KEY_NOTUSED == remove->key) { - /* Key set to NOTUSED means it is a subnode within a 'same' linked list - and thus we can unlink it easily. The 'smaller' link of a subnode - links to the parent node. */ - if (remove->smaller == NULL) - return 3; - - remove->smaller->same = remove->same; - if(remove->same) - remove->same->smaller = remove->smaller; - - /* Ensures that double-remove gets caught. */ - remove->smaller = NULL; - - /* voila, we're done! */ - *newroot = t; /* return the same root */ - return 0; - } - - t = Curl_splay(remove->key, 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 - 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 - could return the same key but a different node. */ - if(t != remove) - return 2; - - /* 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->same; - if(x) { - /* 'x' is the new root node, we just make it use the root node's - smaller/larger links */ - - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - } - else { - /* Remove the root node */ - if (t->smaller == NULL) - x = t->larger; - else { - x = Curl_splay(remove->key, t->smaller); - x->larger = t->larger; - } - } - - *newroot = x; /* store new root pointer */ - - return 0; -} - -#ifdef CURLDEBUG - -void Curl_splayprint(struct Curl_tree * t, int d, char output) -{ - struct Curl_tree *node; - int i; - int count; - if (t == NULL) - return; - - Curl_splayprint(t->larger, d+1, output); - for (i=0; ikey, i); - } - - for(count=0, node = t->same; node; node = node->same, count++) - ; - - if(output) { - if(count) - printf(" [%d more]\n", count); - else - printf("\n"); - } - - Curl_splayprint(t->smaller, d+1, output); -} -#endif - -#ifdef TEST_SPLAY - -/*#define TEST2 */ -#define MAX 50 -#define TEST2 - -/* A sample use of these functions. Start with the empty tree, insert some - stuff into it, and then delete it */ -int main(int argc, char **argv) -{ - struct Curl_tree *root, *t; - void *ptrs[MAX]; - int adds=0; - int rc; - - long sizes[]={ - 50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300, - 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, - 300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, - 200, 300, 220, 80, 90}; - int i; - root = NULL; /* the empty tree */ - - for (i = 0; i < MAX; i++) { - int key; - ptrs[i] = t = (struct Curl_tree *)malloc(sizeof(struct Curl_tree)); - -#ifdef TEST2 - key = sizes[i]; -#elif defined(TEST1) - key = (541*i)%1023; -#elif defined(TEST3) - key = 100; -#endif - - t->payload = (void *)key; /* for simplicity */ - if(!t) { - puts("out of memory!"); - return 0; - } - root = Curl_splayinsert(key, root, t); - } - -#if 0 - puts("Result:"); - Curl_splayprint(root, 0, 1); -#endif - -#if 1 - for (i = 0; i < MAX; i++) { - int rem = (i+7)%MAX; - struct Curl_tree *r; - printf("Tree look:\n"); - Curl_splayprint(root, 0, 1); - printf("remove pointer %d, payload %d\n", rem, - (int)((struct Curl_tree *)ptrs[rem])->payload); - rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root); - if(rc) - /* failed! */ - printf("remove %d failed!\n", rem); - } -#endif - - return 0; -} - -#endif /* TEST_SPLAY */ diff --git a/Utilities/cmcurl/splay.h b/Utilities/cmcurl/splay.h deleted file mode 100644 index 1674534..0000000 --- a/Utilities/cmcurl/splay.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __SPLAY_H -#define __SPLAY_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1997 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -struct Curl_tree { - struct Curl_tree *smaller; /* smaller node */ - struct Curl_tree *larger; /* larger node */ - struct Curl_tree *same; /* points to a node with identical key */ - int key; /* the "sort" key */ - void *payload; /* data the splay code doesn't care about */ -}; - -struct Curl_tree *Curl_splay(int i, struct Curl_tree *t); -struct Curl_tree *Curl_splayinsert(int key, struct Curl_tree *t, - struct Curl_tree *newnode); -#if 0 -struct Curl_tree *Curl_splayremove(int key, struct Curl_tree *t, - struct Curl_tree **removed); -#endif - -struct Curl_tree *Curl_splaygetbest(int key, struct Curl_tree *t, - struct Curl_tree **removed); -int Curl_splayremovebyaddr(struct Curl_tree *t, - struct Curl_tree *remove, - struct Curl_tree **newroot); - -#ifdef CURLDEBUG -void Curl_splayprint(struct Curl_tree * t, int d, char output); -#else -#define Curl_splayprint(x,y,z) -#endif - -#endif diff --git a/Utilities/cmcurl/ssh.c b/Utilities/cmcurl/ssh.c deleted file mode 100644 index 24cba1b..0000000 --- a/Utilities/cmcurl/ssh.c +++ /dev/null @@ -1,979 +0,0 @@ -/*************************************************************************** -* _ _ ____ _ -* Project ___| | | | _ \| | -* / __| | | | |_) | | -* | (__| |_| | _ <| |___ -* \___|\___/|_| \_\_____| -* -* Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. -* -* $Id$ -***************************************************************************/ - -/* #define CURL_LIBSSH2_DEBUG */ - -#include "setup.h" - -#ifdef USE_LIBSSH2 -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_FCNTL_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#ifdef HAVE_TIME_H -#include -#endif - -#ifdef WIN32 - -#else /* probably some kind of unix */ -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_UTSNAME_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef VMS -#include -#include -#endif -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - -#include "if2ip.h" -#include "hostip.h" -#include "progress.h" -#include "transfer.h" -#include "escape.h" -#include "http.h" /* for HTTP proxy tunnel stuff */ -#include "ssh.h" -#include "url.h" -#include "speedcheck.h" -#include "getinfo.h" - -#include "strtoofft.h" -#include "strequal.h" -#include "sslgen.h" -#include "connect.h" -#include "strerror.h" -#include "memory.h" -#include "inet_ntop.h" -#include "select.h" -#include "parsedate.h" /* for the week day and month names */ -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "multiif.h" - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) -#define DIRSEP '\\' -#else -#define DIRSEP '/' -#endif - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#ifdef CURLDEBUG -#include "memdebug.h" -#endif - -#ifndef LIBSSH2_SFTP_S_IRUSR -/* Here's a work-around for those of you who happend to run a libssh2 version - that is 0.14 or older. We should remove this kludge as soon as we can - require a more recent libssh2 release. */ -#ifndef S_IRGRP -#define S_IRGRP 0 -#endif - -#ifndef S_IROTH -#define S_IROTH 0 -#endif - -#define LIBSSH2_SFTP_S_IRUSR S_IRUSR -#define LIBSSH2_SFTP_S_IWUSR S_IWUSR -#define LIBSSH2_SFTP_S_IRGRP S_IRGRP -#define LIBSSH2_SFTP_S_IROTH S_IROTH -#define LIBSSH2_SFTP_S_IRUSR S_IRUSR -#define LIBSSH2_SFTP_S_IWUSR S_IWUSR -#define LIBSSH2_SFTP_S_IRGRP S_IRGRP -#define LIBSSH2_SFTP_S_IROTH S_IROTH -#define LIBSSH2_SFTP_S_IFMT S_IFMT -#define LIBSSH2_SFTP_S_IFDIR S_IFDIR -#define LIBSSH2_SFTP_S_IFLNK S_IFLNK -#define LIBSSH2_SFTP_S_IFSOCK S_IFSOCK -#define LIBSSH2_SFTP_S_IFCHR S_IFCHR -#define LIBSSH2_SFTP_S_IFBLK S_IFBLK -#define LIBSSH2_SFTP_S_IXUSR S_IXUSR -#define LIBSSH2_SFTP_S_IWGRP S_IWGRP -#define LIBSSH2_SFTP_S_IXGRP S_IXGRP -#define LIBSSH2_SFTP_S_IWOTH S_IWOTH -#define LIBSSH2_SFTP_S_IXOTH S_IXOTH -#endif - -static LIBSSH2_ALLOC_FUNC(libssh2_malloc); -static LIBSSH2_REALLOC_FUNC(libssh2_realloc); -static LIBSSH2_FREE_FUNC(libssh2_free); - -static void -kbd_callback(const char *name, int name_len, const char *instruction, - int instruction_len, int num_prompts, - const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, - LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, - void **abstract) -{ - struct SSHPROTO *ssh = (struct SSHPROTO *)*abstract; - -#ifdef CURL_LIBSSH2_DEBUG - fprintf(stderr, "name=%s\n", name); - fprintf(stderr, "name_len=%d\n", name_len); - fprintf(stderr, "instruction=%s\n", instruction); - fprintf(stderr, "instruction_len=%d\n", instruction_len); - fprintf(stderr, "num_prompts=%d\n", num_prompts); -#else - (void)name; - (void)name_len; - (void)instruction; - (void)instruction_len; -#endif /* CURL_LIBSSH2_DEBUG */ - if (num_prompts == 1) { - responses[0].text = strdup(ssh->passwd); - responses[0].length = strlen(ssh->passwd); - } - (void)prompts; - (void)abstract; -} /* kbd_callback */ - -static CURLcode libssh2_error_to_CURLE(struct connectdata *conn) -{ - int errorcode; - struct SSHPROTO *scp = conn->data->reqdata.proto.ssh; - - /* Get the libssh2 error code and string */ - errorcode = libssh2_session_last_error(scp->ssh_session, &scp->errorstr, - NULL, 0); - if (errorcode == LIBSSH2_FX_OK) - return CURLE_OK; - - infof(conn->data, "libssh2 error %d, '%s'\n", errorcode, scp->errorstr); - - /* TODO: map some of the libssh2 errors to the more appropriate CURLcode - error code, and possibly add a few new SSH-related one. We must however - not return or even depend on libssh2 errors in the public libcurl API */ - - return CURLE_SSH; -} - -static LIBSSH2_ALLOC_FUNC(libssh2_malloc) -{ - return malloc(count); - (void)abstract; -} - -static LIBSSH2_REALLOC_FUNC(libssh2_realloc) -{ - return realloc(ptr, count); - (void)abstract; -} - -static LIBSSH2_FREE_FUNC(libssh2_free) -{ - free(ptr); - (void)abstract; -} - -static CURLcode ssh_init(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - struct SSHPROTO *ssh; - if (data->reqdata.proto.ssh) - return CURLE_OK; - - ssh = (struct SSHPROTO *)calloc(sizeof(struct SSHPROTO), 1); - if (!ssh) - return CURLE_OUT_OF_MEMORY; - - data->reqdata.proto.ssh = ssh; - - /* get some initial data into the ssh struct */ - ssh->bytecountp = &data->reqdata.keep.bytecount; - - /* no need to duplicate them, this connectdata struct won't change */ - ssh->user = conn->user; - ssh->passwd = conn->passwd; - - ssh->errorstr = NULL; - - ssh->ssh_session = NULL; - ssh->ssh_channel = NULL; - ssh->sftp_session = NULL; - ssh->sftp_handle = NULL; - - return CURLE_OK; -} - -/* - * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to - * do protocol-specific actions at connect-time. - */ -CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done) -{ - int i; - struct SSHPROTO *ssh; - const char *fingerprint; - const char *authlist; - char *home; - char rsa_pub[PATH_MAX]; - char rsa[PATH_MAX]; - char tempHome[PATH_MAX]; - curl_socket_t sock; - char *real_path; - char *working_path; - int working_path_len; - bool authed = FALSE; - CURLcode result; - struct SessionHandle *data = conn->data; - - rsa_pub[0] = rsa[0] = '\0'; - - result = ssh_init(conn); - if (result) - return result; - - ssh = data->reqdata.proto.ssh; - - working_path = curl_easy_unescape(data, data->reqdata.path, 0, - &working_path_len); - if (!working_path) - return CURLE_OUT_OF_MEMORY; - -#ifdef CURL_LIBSSH2_DEBUG - if (ssh->user) { - infof(data, "User: %s\n", ssh->user); - } - if (ssh->passwd) { - infof(data, "Password: %s\n", ssh->passwd); - } -#endif /* CURL_LIBSSH2_DEBUG */ - sock = conn->sock[FIRSTSOCKET]; - ssh->ssh_session = libssh2_session_init_ex(libssh2_malloc, libssh2_free, - libssh2_realloc, ssh); - if (ssh->ssh_session == NULL) { - failf(data, "Failure initialising ssh session\n"); - Curl_safefree(ssh->path); - return CURLE_FAILED_INIT; - } -#ifdef CURL_LIBSSH2_DEBUG - infof(data, "SSH socket: %d\n", sock); -#endif /* CURL_LIBSSH2_DEBUG */ - - if (libssh2_session_startup(ssh->ssh_session, sock)) { - failf(data, "Failure establishing ssh session\n"); - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - Curl_safefree(ssh->path); - return CURLE_FAILED_INIT; - } - - /* - * Before we authenticate we should check the hostkey's fingerprint against - * our known hosts. How that is handled (reading from file, whatever) is - * up to us. As for know not much is implemented, besides showing how to - * get the fingerprint. - */ - fingerprint = libssh2_hostkey_hash(ssh->ssh_session, - LIBSSH2_HOSTKEY_HASH_MD5); - -#ifdef CURL_LIBSSH2_DEBUG - /* The fingerprint points to static storage (!), don't free() it. */ - infof(data, "Fingerprint: "); - for (i = 0; i < 16; i++) { - infof(data, "%02X ", (unsigned char) fingerprint[i]); - } - infof(data, "\n"); -#endif /* CURL_LIBSSH2_DEBUG */ - - /* TBD - methods to check the host keys need to be done */ - - /* - * Figure out authentication methods - * NB: As soon as we have provided a username to an openssh server we 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 won't work in my experience. - * So always specify it here. - */ - authlist = libssh2_userauth_list(ssh->ssh_session, ssh->user, - strlen(ssh->user)); - - /* - * Check the supported auth types in the order I feel is most secure with the - * requested type of authentication - */ - if ((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && - (strstr(authlist, "publickey") != NULL)) { - /* To ponder about: should really the lib be messing about with the HOME - environment variable etc? */ - home = curl_getenv("HOME"); - - if (data->set.ssh_public_key) - snprintf(rsa_pub, sizeof(rsa_pub), "%s", data->set.ssh_public_key); - else if (home) - snprintf(rsa_pub, sizeof(rsa_pub), "%s/.ssh/id_dsa.pub", home); - - if (data->set.ssh_private_key) - snprintf(rsa, sizeof(rsa), "%s", data->set.ssh_private_key); - else if (home) - snprintf(rsa, sizeof(rsa), "%s/.ssh/id_dsa", home); - - curl_free(home); - - if (rsa_pub[0]) { - /* The function below checks if the files exists, no need to stat() here. - */ - if (libssh2_userauth_publickey_fromfile(ssh->ssh_session, ssh->user, - rsa_pub, rsa, "") == 0) { - authed = TRUE; - } - } - } - if (!authed && - (data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) && - (strstr(authlist, "password") != NULL)) { - if (!libssh2_userauth_password(ssh->ssh_session, ssh->user, ssh->passwd)) - authed = TRUE; - } - if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_HOST) && - (strstr(authlist, "hostbased") != NULL)) { - } - if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) - && (strstr(authlist, "keyboard-interactive") != NULL)) { - /* Authentication failed. Continue with keyboard-interactive now. */ - if (libssh2_userauth_keyboard_interactive_ex(ssh->ssh_session, ssh->user, - strlen(ssh->user), - &kbd_callback) == 0) { - authed = TRUE; - } - } - - if (!authed) { - failf(data, "Authentication failure\n"); - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - Curl_safefree(ssh->path); - return CURLE_FAILED_INIT; - } - - /* - * At this point we have an authenticated ssh session. - */ - conn->sockfd = sock; - conn->writesockfd = CURL_SOCKET_BAD; - - if (conn->protocol == PROT_SFTP) { - /* - * Start the libssh2 sftp session - */ - ssh->sftp_session = libssh2_sftp_init(ssh->ssh_session); - if (ssh->sftp_session == NULL) { - failf(data, "Failure initialising sftp session\n"); - libssh2_sftp_shutdown(ssh->sftp_session); - ssh->sftp_session = NULL; - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - return CURLE_FAILED_INIT; - } - - /* - * Get the "home" directory - */ - i = libssh2_sftp_realpath(ssh->sftp_session, ".", tempHome, PATH_MAX-1); - if (i > 0) { - /* It seems that this string is not always NULL terminated */ - tempHome[i] = '\0'; - ssh->homedir = (char *)strdup(tempHome); - if (!ssh->homedir) { - libssh2_sftp_shutdown(ssh->sftp_session); - ssh->sftp_session = NULL; - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - return CURLE_OUT_OF_MEMORY; - } - } - else { - /* Return the error type */ - i = libssh2_sftp_last_error(ssh->sftp_session); - DEBUGF(infof(data, "error = %d\n", i)); - } - } - - /* Check for /~/ , indicating realative to the users home directory */ - if (conn->protocol == PROT_SCP) { - real_path = (char *)malloc(working_path_len+1); - if (real_path == NULL) { - Curl_safefree(working_path); - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - return CURLE_OUT_OF_MEMORY; - } - if (working_path[1] == '~') - /* It is referenced to the home directory, so strip the leading '/' */ - memcpy(real_path, working_path+1, 1 + working_path_len-1); - else - memcpy(real_path, working_path, 1 + working_path_len); - } - else if (conn->protocol == PROT_SFTP) { - if (working_path[1] == '~') { - real_path = (char *)malloc(strlen(ssh->homedir) + - working_path_len + 1); - if (real_path == NULL) { - libssh2_sftp_shutdown(ssh->sftp_session); - ssh->sftp_session = NULL; - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - Curl_safefree(working_path); - return CURLE_OUT_OF_MEMORY; - } - /* It is referenced to the home directory, so strip the leading '/' */ - memcpy(real_path, ssh->homedir, strlen(ssh->homedir)); - real_path[strlen(ssh->homedir)] = '/'; - real_path[strlen(ssh->homedir)+1] = '\0'; - if (working_path_len > 3) { - memcpy(real_path+strlen(ssh->homedir)+1, working_path + 3, - 1 + working_path_len -3); - } - } - else { - real_path = (char *)malloc(working_path_len+1); - if (real_path == NULL) { - libssh2_session_free(ssh->ssh_session); - ssh->ssh_session = NULL; - Curl_safefree(working_path); - return CURLE_OUT_OF_MEMORY; - } - memcpy(real_path, working_path, 1+working_path_len); - } - } - else - return CURLE_FAILED_INIT; - - Curl_safefree(working_path); - ssh->path = real_path; - - *done = TRUE; - return CURLE_OK; -} - -CURLcode Curl_scp_do(struct connectdata *conn, bool *done) -{ - struct stat sb; - struct SSHPROTO *scp = conn->data->reqdata.proto.ssh; - CURLcode res = CURLE_OK; - - *done = TRUE; /* unconditionally */ - - if (conn->data->set.upload) { - /* - * NOTE!!! libssh2 requires that the destination path is a full path - * that 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. - */ - scp->ssh_channel = libssh2_scp_send_ex(scp->ssh_session, scp->path, - LIBSSH2_SFTP_S_IRUSR| - LIBSSH2_SFTP_S_IWUSR| - LIBSSH2_SFTP_S_IRGRP| - LIBSSH2_SFTP_S_IROTH, - conn->data->set.infilesize, 0, 0); - if (!scp->ssh_channel) - return CURLE_FAILED_INIT; - - /* upload data */ - res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - } - else { - /* - * We must check the remote file, if it is a directory no vaules will - * be set in sb - */ - curl_off_t bytecount; - memset(&sb, 0, sizeof(struct stat)); - scp->ssh_channel = libssh2_scp_recv(scp->ssh_session, scp->path, &sb); - if (!scp->ssh_channel) { - if ((sb.st_mode == 0) && (sb.st_atime == 0) && (sb.st_mtime == 0) && - (sb.st_size == 0)) { - /* Since sb is still empty, it is likely the file was not found */ - return CURLE_REMOTE_FILE_NOT_FOUND; - } - return libssh2_error_to_CURLE(conn); - } - /* download data */ - bytecount = (curl_off_t) sb.st_size; - conn->data->reqdata.maxdownload = (curl_off_t) sb.st_size; - res = Curl_setup_transfer(conn, FIRSTSOCKET, - bytecount, FALSE, NULL, -1, NULL); - } - - return res; -} - -CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - struct SSHPROTO *scp = conn->data->reqdata.proto.ssh; - (void)premature; /* not used */ - - Curl_safefree(scp->path); - scp->path = NULL; - - if (scp->ssh_channel) { - if (libssh2_channel_close(scp->ssh_channel) < 0) { - infof(conn->data, "Failed to stop libssh2 channel subsystem\n"); - } - } - - if (scp->ssh_session) { - libssh2_session_disconnect(scp->ssh_session, "Shutdown"); - libssh2_session_free(scp->ssh_session); - scp->ssh_session = NULL; - } - - free(conn->data->reqdata.proto.ssh); - conn->data->reqdata.proto.ssh = NULL; - Curl_pgrsDone(conn); - - (void)status; /* unused */ - - return CURLE_OK; -} - -/* return number of received (decrypted) bytes */ -ssize_t Curl_scp_send(struct connectdata *conn, int sockindex, - void *mem, size_t len) -{ - ssize_t nwrite; - - /* libssh2_channel_write() returns int - * - * NOTE: we should not store nor rely on connection-related data to be - * in the SessionHandle struct - */ - nwrite = (ssize_t) - libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel, - mem, len); - (void)sockindex; - return nwrite; -} - -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ -ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len) -{ - ssize_t nread; - - /* libssh2_channel_read() returns int - * - * NOTE: we should not store nor rely on connection-related data to be - * in the SessionHandle struct - */ - - nread = (ssize_t) - libssh2_channel_read(conn->data->reqdata.proto.ssh->ssh_channel, - mem, len); - (void)sockindex; - return nread; -} - -/* - * =============== SFTP =============== - */ - -CURLcode Curl_sftp_do(struct connectdata *conn, bool *done) -{ - LIBSSH2_SFTP_ATTRIBUTES attrs; - struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh; - CURLcode res = CURLE_OK; - struct SessionHandle *data = conn->data; - curl_off_t bytecount = 0; - char *buf = data->state.buffer; - - *done = TRUE; /* unconditionally */ - - if (data->set.upload) { - /* - * NOTE!!! libssh2 requires that the destination path is a full path - * that 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. - */ - sftp->sftp_handle = - libssh2_sftp_open(sftp->sftp_session, sftp->path, - LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT, - LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR| - LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH); - if (!sftp->sftp_handle) - return CURLE_FAILED_INIT; - - /* upload data */ - res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - } - else { - if (sftp->path[strlen(sftp->path)-1] == '/') { - /* - * This is a directory that we are trying to get, so produce a - * directory listing - * - * **BLOCKING behaviour** This should be made into a state machine and - * get a separate function called from Curl_sftp_recv() when there is - * data to read from the network, instead of "hanging" here. - */ - char filename[PATH_MAX+1]; - int len, totalLen, currLen; - char *line; - - sftp->sftp_handle = - libssh2_sftp_opendir(sftp->sftp_session, sftp->path); - if (!sftp->sftp_handle) - return CURLE_SSH; - - while ((len = libssh2_sftp_readdir(sftp->sftp_handle, filename, - PATH_MAX, &attrs)) > 0) { - filename[len] = '\0'; - - if (data->set.ftp_list_only) { - if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && - ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFDIR)) { - infof(data, "%s\n", filename); - } - } - else { - totalLen = 80 + len; - line = (char *)malloc(totalLen); - if (!line) - return CURLE_OUT_OF_MEMORY; - - if (!(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID)) - attrs.uid = attrs.gid =0; - - currLen = snprintf(line, totalLen, "---------- 1 %5d %5d", - attrs.uid, attrs.gid); - - if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFDIR) { - line[0] = 'd'; - } - else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFLNK) { - line[0] = 'l'; - } - else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFSOCK) { - line[0] = 's'; - } - else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFCHR) { - line[0] = 'c'; - } - else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFBLK) { - line[0] = 'b'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IRUSR) { - line[1] = 'r'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IWUSR) { - line[2] = 'w'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IXUSR) { - line[3] = 'x'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IRGRP) { - line[4] = 'r'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IWGRP) { - line[5] = 'w'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IXGRP) { - line[6] = 'x'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IROTH) { - line[7] = 'r'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IWOTH) { - line[8] = 'w'; - } - if (attrs.permissions & LIBSSH2_SFTP_S_IXOTH) { - line[9] = 'x'; - } - } - if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { - currLen += snprintf(line+currLen, totalLen-currLen, "%11lld", - attrs.filesize); - } - if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - const char *months[12] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - struct tm *nowParts; - time_t now, remoteTime; - - now = time(NULL); - remoteTime = (time_t)attrs.mtime; - nowParts = localtime(&remoteTime); - - if ((time_t)attrs.mtime > (now - (3600 * 24 * 180))) { - currLen += snprintf(line+currLen, totalLen-currLen, - " %s %2d %2d:%02d", months[nowParts->tm_mon], - nowParts->tm_mday, nowParts->tm_hour, - nowParts->tm_min); - } - else { - currLen += snprintf(line+currLen, totalLen-currLen, - " %s %2d %5d", months[nowParts->tm_mon], - nowParts->tm_mday, 1900+nowParts->tm_year); - } - } - currLen += snprintf(line+currLen, totalLen-currLen, " %s", filename); - if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && - ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) == - LIBSSH2_SFTP_S_IFLNK)) { - char linkPath[PATH_MAX + 1]; - - snprintf(linkPath, PATH_MAX, "%s%s", sftp->path, filename); - len = libssh2_sftp_readlink(sftp->sftp_session, linkPath, filename, - PATH_MAX); - line = realloc(line, totalLen + 4 + len); - if (!line) - return CURLE_OUT_OF_MEMORY; - - currLen += snprintf(line+currLen, totalLen-currLen, " -> %s", - filename); - } - - currLen += snprintf(line+currLen, totalLen-currLen, "\n"); - res = Curl_client_write(conn, CLIENTWRITE_BODY, line, 0); - free(line); - } - } - libssh2_sftp_closedir(sftp->sftp_handle); - sftp->sftp_handle = NULL; - - /* no data to transfer */ - res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - } - else { - /* - * Work on getting the specified file - */ - sftp->sftp_handle = - libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_READ, - LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR| - LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH); - if (!sftp->sftp_handle) - return CURLE_SSH; - - if (libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs)) { - /* - * libssh2_sftp_open() didn't return an error, so maybe the server - * just doesn't support stat() - */ - data->reqdata.size = -1; - data->reqdata.maxdownload = -1; - } - else { - data->reqdata.size = attrs.filesize; - data->reqdata.maxdownload = attrs.filesize; - Curl_pgrsSetDownloadSize(data, attrs.filesize); - } - - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - - /* Now download data. The libssh2 0.14 doesn't offer any way to do this - without using this BLOCKING approach, so here's room for improvement - once libssh2 can return EWOULDBLOCK to us. */ -#if 0 - /* code left here just because this is what this function will use the - day libssh2 is improved */ - res = Curl_setup_transfer(conn, FIRSTSOCKET, - bytecount, FALSE, NULL, -1, NULL); -#endif - while (res == CURLE_OK) { - size_t nread; - /* NOTE: most *read() functions return ssize_t but this returns size_t - which normally is unsigned! */ - nread = libssh2_sftp_read(data->reqdata.proto.ssh->sftp_handle, - buf, BUFSIZE-1); - - if (nread > 0) - buf[nread] = 0; - - /* this check can be changed to a <= 0 when nread is changed to a - signed variable type */ - if ((nread == 0) || (nread == (size_t)~0)) - break; - - bytecount += nread; - - res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); - if(res) - return res; - - Curl_pgrsSetDownloadCounter(data, bytecount); - - if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; - else { - struct timeval now = Curl_tvnow(); - res = Curl_speedcheck(data, now); - } - } - if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; - - /* no (more) data to transfer */ - res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - } - } - - return res; -} - -CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh; - (void)premature; /* not used */ - - Curl_safefree(sftp->path); - sftp->path = NULL; - - Curl_safefree(sftp->homedir); - sftp->homedir = NULL; - - if (sftp->sftp_handle) { - if (libssh2_sftp_close(sftp->sftp_handle) < 0) { - infof(conn->data, "Failed to close libssh2 file\n"); - } - } - - if (sftp->sftp_session) { - if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) { - infof(conn->data, "Failed to stop libssh2 sftp subsystem\n"); - } - } - - if (sftp->ssh_channel) { - if (libssh2_channel_close(sftp->ssh_channel) < 0) { - infof(conn->data, "Failed to stop libssh2 channel subsystem\n"); - } - } - - if (sftp->ssh_session) { - libssh2_session_disconnect(sftp->ssh_session, "Shutdown"); - libssh2_session_free(sftp->ssh_session); - sftp->ssh_session = NULL; - } - - free(conn->data->reqdata.proto.ssh); - conn->data->reqdata.proto.ssh = NULL; - Curl_pgrsDone(conn); - - (void)status; /* unused */ - - return CURLE_OK; -} - -/* return number of received (decrypted) bytes */ -ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex, - void *mem, size_t len) -{ - ssize_t nwrite; - - /* libssh2_sftp_write() returns size_t !*/ - - nwrite = (ssize_t) - libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); - (void)sockindex; - return nwrite; -} - -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ -ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len) -{ - ssize_t nread; - - /* libssh2_sftp_read() returns size_t !*/ - - nread = (ssize_t) - libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); - (void)sockindex; - return nread; -} - -#endif /* USE_LIBSSH2 */ diff --git a/Utilities/cmcurl/ssh.h b/Utilities/cmcurl/ssh.h deleted file mode 100644 index d914490..0000000 --- a/Utilities/cmcurl/ssh.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __SSH_H -#define __SSH_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifdef USE_LIBSSH2 - -CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done); - -CURLcode Curl_scp_do(struct connectdata *conn, bool *done); -CURLcode Curl_scp_done(struct connectdata *conn, CURLcode, bool premature); - -ssize_t Curl_scp_send(struct connectdata *conn, int sockindex, - void *mem, size_t len); -ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len); - -CURLcode Curl_sftp_do(struct connectdata *conn, bool *done); -CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode, bool premature); - -ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex, - void *mem, size_t len); -ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex, - char *mem, size_t len); - -#endif /* USE_LIBSSH2 */ - -#endif /* __SSH_H */ diff --git a/Utilities/cmcurl/sslgen.c b/Utilities/cmcurl/sslgen.c deleted file mode 100644 index f110a51..0000000 --- a/Utilities/cmcurl/sslgen.c +++ /dev/null @@ -1,618 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* This file is for "generic" SSL functions that all libcurl internals should - use. It is responsible for calling the proper 'ossl' function in ssluse.c - (OpenSSL based) or the 'gtls' function in gtls.c (GnuTLS based). - - SSL-functions in libcurl should call functions in this source file, and not - to any specific SSL-layer. - - Curl_ssl_ - prefix for generic ones - Curl_ossl_ - prefix for OpenSSL ones - Curl_gtls_ - prefix for GnuTLS ones - - "SSL/TLS Strong Encryption: An Introduction" - http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html -*/ - -#include "setup.h" -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "urldata.h" -#define SSLGEN_C -#include "sslgen.h" /* generic SSL protos etc */ -#include "ssluse.h" /* OpenSSL versions */ -#include "gtls.h" /* GnuTLS versions */ -#include "sendf.h" -#include "strequal.h" -#include "url.h" -#include "memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* "global" init done? */ -static bool init_ssl=FALSE; - -static bool safe_strequal(char* str1, char* str2); - -static bool safe_strequal(char* str1, char* str2) -{ - if(str1 && str2) - /* both pointers point to something then compare them */ - return (bool)(0 != strequal(str1, str2)); - else - /* if both pointers are NULL then treat them as equal */ - return (bool)(!str1 && !str2); -} - -bool -Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle) -{ - if((data->version == needle->version) && - (data->verifypeer == needle->verifypeer) && - (data->verifyhost == needle->verifyhost) && - safe_strequal(data->CApath, needle->CApath) && - safe_strequal(data->CAfile, needle->CAfile) && - safe_strequal(data->random_file, needle->random_file) && - safe_strequal(data->egdsocket, needle->egdsocket) && - safe_strequal(data->cipher_list, needle->cipher_list)) - return TRUE; - - return FALSE; -} - -bool -Curl_clone_ssl_config(struct ssl_config_data *source, - struct ssl_config_data *dest) -{ - dest->verifyhost = source->verifyhost; - dest->verifypeer = source->verifypeer; - dest->version = source->version; - - if(source->CAfile) { - dest->CAfile = strdup(source->CAfile); - if(!dest->CAfile) - return FALSE; - } - - if(source->CApath) { - dest->CApath = strdup(source->CApath); - if(!dest->CApath) - return FALSE; - } - - if(source->cipher_list) { - dest->cipher_list = strdup(source->cipher_list); - if(!dest->cipher_list) - return FALSE; - } - - if(source->egdsocket) { - dest->egdsocket = strdup(source->egdsocket); - if(!dest->egdsocket) - return FALSE; - } - - if(source->random_file) { - dest->random_file = strdup(source->random_file); - if(!dest->random_file) - return FALSE; - } - - return TRUE; -} - -void Curl_free_ssl_config(struct ssl_config_data* sslc) -{ - if(sslc->CAfile) - free(sslc->CAfile); - - if(sslc->CApath) - free(sslc->CApath); - - if(sslc->cipher_list) - free(sslc->cipher_list); - - if(sslc->egdsocket) - free(sslc->egdsocket); - - if(sslc->random_file) - free(sslc->random_file); -} - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -int Curl_ssl_init(void) -{ - /* make sure this is only done once */ - if(init_ssl) - return 1; - init_ssl = TRUE; /* never again */ - -#ifdef USE_SSLEAY - return Curl_ossl_init(); -#else -#ifdef USE_GNUTLS - return Curl_gtls_init(); -#else - /* no SSL support */ - return 1; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -} - - -/* Global cleanup */ -void Curl_ssl_cleanup(void) -{ - if(init_ssl) { - /* only cleanup if we did a previous init */ -#ifdef USE_SSLEAY - Curl_ossl_cleanup(); -#else -#ifdef USE_GNUTLS - Curl_gtls_cleanup(); -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ - init_ssl = FALSE; - } -} - -CURLcode -Curl_ssl_connect(struct connectdata *conn, int sockindex) -{ -#ifdef USE_SSL - /* mark this is being ssl enabled from here on. */ - conn->ssl[sockindex].use = TRUE; - -#ifdef USE_SSLEAY - return Curl_ossl_connect(conn, sockindex); -#else -#ifdef USE_GNUTLS - return Curl_gtls_connect(conn, sockindex); -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ - -#else - /* without SSL */ - (void)conn; - (void)sockindex; - return CURLE_OK; -#endif /* USE_SSL */ -} - -CURLcode -Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, - bool *done) -{ -#if defined(USE_SSL) && defined(USE_SSLEAY) - /* mark this is being ssl enabled from here on. */ - conn->ssl[sockindex].use = TRUE; - return Curl_ossl_connect_nonblocking(conn, sockindex, done); - -#else - /* not implemented! - fallback to BLOCKING call. */ - *done = TRUE; - return Curl_ssl_connect(conn, sockindex); -#endif -} - -#ifdef USE_SSL - -/* - * 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. - */ -int Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */ -{ - struct curl_ssl_session *check; - struct SessionHandle *data = conn->data; - long i; - - if(!conn->ssl_config.sessionid) - /* session ID re-use is disabled */ - return TRUE; - - for(i=0; i< data->set.ssl.numsessions; i++) { - check = &data->state.session[i]; - if(!check->sessionid) - /* not session ID means blank entry */ - continue; - if(curl_strequal(conn->host.name, check->name) && - (conn->remote_port == check->remote_port) && - Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { - /* yes, we have a session ID! */ - data->state.sessionage++; /* increase general age */ - check->age = data->state.sessionage; /* set this as used in this age */ - *ssl_sessionid = check->sessionid; - if(idsize) - *idsize = check->idsize; - return FALSE; - } - } - *ssl_sessionid = NULL; - return TRUE; -} - -/* - * Kill a single session ID entry in the cache. - */ -static int kill_session(struct curl_ssl_session *session) -{ - if(session->sessionid) { - /* defensive check */ - - /* free the ID the SSL-layer specific way */ -#ifdef USE_SSLEAY - Curl_ossl_session_free(session->sessionid); -#else - Curl_gtls_session_free(session->sessionid); -#endif - session->sessionid=NULL; - session->age = 0; /* fresh */ - - Curl_free_ssl_config(&session->ssl_config); - - Curl_safefree(session->name); - session->name = NULL; /* no name */ - - return 0; /* ok */ - } - else - return 1; -} - -/* - * 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 connectdata *conn, - void *ssl_sessionid, - size_t idsize) -{ - int i; - struct SessionHandle *data=conn->data; /* the mother of all structs */ - struct curl_ssl_session *store = &data->state.session[0]; - long oldest_age=data->state.session[0].age; /* zero if unused */ - char *clone_host; - - /* Even though session ID re-use might be disabled, that only disables USING - IT. We still store it here in case the re-using is again enabled for an - upcoming transfer */ - - clone_host = strdup(conn->host.name); - if(!clone_host) - return CURLE_OUT_OF_MEMORY; /* bail out */ - - /* Now we should add the session ID and the host name to the cache, (remove - the oldest if necessary) */ - - /* find an empty slot for us, or find the oldest */ - for(i=1; (iset.ssl.numsessions) && - data->state.session[i].sessionid; i++) { - if(data->state.session[i].age < oldest_age) { - oldest_age = data->state.session[i].age; - store = &data->state.session[i]; - } - } - if(i == data->set.ssl.numsessions) - /* cache is full, we must "kill" the oldest entry! */ - kill_session(store); - else - store = &data->state.session[i]; /* use this slot */ - - /* now init the session struct wisely */ - store->sessionid = ssl_sessionid; - store->idsize = idsize; - store->age = data->state.sessionage; /* set current age */ - store->name = clone_host; /* clone host name */ - store->remote_port = conn->remote_port; /* port number */ - - if (!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - - -#endif - -void Curl_ssl_close_all(struct SessionHandle *data) -{ -#ifdef USE_SSL - int i; - /* kill the session ID cache */ - if(data->state.session) { - for(i=0; i< data->set.ssl.numsessions; i++) - /* the single-killer function handles empty table slots */ - kill_session(&data->state.session[i]); - - /* free the cache data */ - free(data->state.session); - data->state.session = NULL; - } -#ifdef USE_SSLEAY - Curl_ossl_close_all(data); -#else -#ifdef USE_GNUTLS - Curl_gtls_close_all(data); -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -#else /* USE_SSL */ - (void)data; -#endif /* USE_SSL */ -} - -void Curl_ssl_close(struct connectdata *conn) -{ - if(conn->ssl[FIRSTSOCKET].use) { -#ifdef USE_SSLEAY - Curl_ossl_close(conn); -#else -#ifdef USE_GNUTLS - Curl_gtls_close(conn); -#else - (void)conn; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ - } -} - -CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) -{ - if(conn->ssl[sockindex].use) { -#ifdef USE_SSLEAY - if(Curl_ossl_shutdown(conn, sockindex)) - return CURLE_SSL_SHUTDOWN_FAILED; -#else -#ifdef USE_GNUTLS - if(Curl_gtls_shutdown(conn, sockindex)) - return CURLE_SSL_SHUTDOWN_FAILED; -#else - (void)conn; - (void)sockindex; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ - } - return CURLE_OK; -} - -/* Selects an (Open)SSL crypto engine - */ -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) -{ -#ifdef USE_SSLEAY - return Curl_ossl_set_engine(data, engine); -#else -#ifdef USE_GNUTLS - /* FIX: add code here */ - (void)data; - (void)engine; - return CURLE_FAILED_INIT; -#else - /* no SSL layer */ - (void)data; - (void)engine; - return CURLE_FAILED_INIT; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -} - -/* Selects an (Open?)SSL crypto engine - */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) -{ -#ifdef USE_SSLEAY - return Curl_ossl_set_engine_default(data); -#else -#ifdef USE_GNUTLS - /* FIX: add code here */ - (void)data; - return CURLE_FAILED_INIT; -#else - /* No SSL layer */ - (void)data; - return CURLE_FAILED_INIT; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -} - -/* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) -{ -#ifdef USE_SSLEAY - return Curl_ossl_engines_list(data); -#else -#ifdef USE_GNUTLS - /* FIX: add code here? */ - (void)data; - return NULL; -#else - (void)data; - return NULL; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -} - -/* return number of sent (non-SSL) bytes */ -ssize_t Curl_ssl_send(struct connectdata *conn, - int sockindex, - void *mem, - size_t len) -{ -#ifdef USE_SSLEAY - return Curl_ossl_send(conn, sockindex, mem, len); -#else -#ifdef USE_GNUTLS - return Curl_gtls_send(conn, sockindex, mem, len); -#else - (void)conn; - (void)sockindex; - (void)mem; - (void)len; - return 0; -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -} - -/* return number of received (decrypted) bytes */ - -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ -ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - char *mem, /* store read data here */ - size_t len) /* max amount to read */ -{ -#ifdef USE_SSL - ssize_t nread; - bool block = FALSE; - -#ifdef USE_SSLEAY - nread = Curl_ossl_recv(conn, sockindex, mem, len, &block); -#else -#ifdef USE_GNUTLS - nread = Curl_gtls_recv(conn, sockindex, mem, len, &block); -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ - if(nread == -1) { - if(!block) - return 0; /* this is a true error, not EWOULDBLOCK */ - else - return -1; - } - - return (int)nread; - -#else /* USE_SSL */ - (void)conn; - (void)sockindex; - (void)mem; - (void)len; - return 0; -#endif /* USE_SSL */ -} - - -/* - * This sets up a session ID cache to the specified size. Make sure this code - * is agnostic to what underlying SSL technology we use. - */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount) -{ -#ifdef USE_SSL - struct curl_ssl_session *session; - - if(data->state.session) - /* this is just a precaution to prevent multiple inits */ - return CURLE_OK; - - session = (struct curl_ssl_session *) - calloc(sizeof(struct curl_ssl_session), amount); - if(!session) - return CURLE_OUT_OF_MEMORY; - - /* store the info in the SSL section */ - data->set.ssl.numsessions = amount; - data->state.session = session; - data->state.sessionage = 1; /* this is brand new */ -#else - /* without SSL, do nothing */ - (void)data; - (void)amount; -#endif - - return CURLE_OK; -} - -size_t Curl_ssl_version(char *buffer, size_t size) -{ -#ifdef USE_SSLEAY - return Curl_ossl_version(buffer, size); -#else -#ifdef USE_GNUTLS - return Curl_gtls_version(buffer, size); -#else - (void)buffer; - (void)size; - return 0; /* no SSL support */ -#endif /* USE_GNUTLS */ -#endif /* USE_SSLEAY */ -} - - -/* - * This function tries to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -int Curl_ssl_check_cxn(struct connectdata *conn) -{ -#ifdef USE_SSLEAY - return Curl_ossl_check_cxn(conn); -#else - (void)conn; - /* TODO: we lack implementation of this for GnuTLS */ - return -1; /* connection status unknown */ -#endif /* USE_SSLEAY */ -} - -bool Curl_ssl_data_pending(struct connectdata *conn, - int connindex) -{ -#ifdef USE_SSLEAY - /* OpenSSL-specific */ - if(conn->ssl[connindex].handle) - /* SSL is in use */ - return SSL_pending(conn->ssl[connindex].handle); -#else - (void)conn; - (void)connindex; -#endif - return FALSE; /* nothing pending */ - -} diff --git a/Utilities/cmcurl/sslgen.h b/Utilities/cmcurl/sslgen.h deleted file mode 100644 index c24d46b..0000000 --- a/Utilities/cmcurl/sslgen.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __SSLGEN_H -#define __SSLGEN_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -bool Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle); -bool Curl_clone_ssl_config(struct ssl_config_data* source, - struct ssl_config_data* dest); -void Curl_free_ssl_config(struct ssl_config_data* sslc); - -int Curl_ssl_init(void); -void Curl_ssl_cleanup(void); -CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -void Curl_ssl_close(struct connectdata *conn); -/* tell the SSL stuff to close down all open information regarding - connections (and thus session ID caching etc) */ -void Curl_ssl_close_all(struct SessionHandle *data); -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine); -/* Sets engine as default for all SSL operations */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data); -ssize_t Curl_ssl_send(struct connectdata *conn, - int sockindex, - void *mem, - size_t len); -ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - char *mem, /* store read data here */ - size_t len); /* max amount to read */ - -/* init the SSL session ID cache */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *, long); -/* extract a session ID */ -int Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */; -/* add a new session ID */ -CURLcode Curl_ssl_addsessionid(struct connectdata *conn, - void *ssl_sessionid, - size_t idsize); - - -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data); - -size_t Curl_ssl_version(char *buffer, size_t size); - -int Curl_ssl_check_cxn(struct connectdata *conn); - -CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); - -bool Curl_ssl_data_pending(struct connectdata *conn, - int connindex); - -#if !defined(USE_SSL) && !defined(SSLGEN_C) -/* set up blank macros for none-SSL builds */ -#define Curl_ssl_close_all(x) -#endif - -#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ - -#endif diff --git a/Utilities/cmcurl/ssluse.c b/Utilities/cmcurl/ssluse.c deleted file mode 100644 index 6709278..0000000 --- a/Utilities/cmcurl/ssluse.c +++ /dev/null @@ -1,1950 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code - * but sslgen.c should ever call or use these functions. - */ - -/* - * The original SSLeay-using code for curl was written by Linas Vepstas and - * Sampo Kellomaki 1998. - */ - -#include "setup.h" - -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "formdata.h" /* for the boundary function */ -#include "url.h" /* for the ssl config check function */ -#include "inet_pton.h" -#include "ssluse.h" -#include "connect.h" /* Curl_sockerrno() proto */ -#include "strequal.h" -#include "select.h" -#include "sslgen.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - -#ifdef USE_SSLEAY - -#ifdef USE_OPENSSL -#include -#include -#else -#include -#include -#endif - -#include "memory.h" -#include "easyif.h" /* for Curl_convert_from_utf8 prototype */ - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x0090581fL -#define HAVE_SSL_GET1_SESSION 1 -#else -#undef HAVE_SSL_GET1_SESSION -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00904100L -#define HAVE_USERDATA_IN_PWD_CALLBACK 1 -#else -#undef HAVE_USERDATA_IN_PWD_CALLBACK -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00907001L -/* ENGINE_load_private_key() takes four arguments */ -#define HAVE_ENGINE_LOAD_FOUR_ARGS -#else -/* ENGINE_load_private_key() takes three arguments */ -#undef HAVE_ENGINE_LOAD_FOUR_ARGS -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H) -/* OpenSSL has PKCS 12 support */ -#define HAVE_PKCS12_SUPPORT -#else -/* OpenSSL/SSLEay does not have PKCS12 support */ -#undef HAVE_PKCS12_SUPPORT -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00906001L -#define HAVE_ERR_ERROR_STRING_N 1 -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00909000L -#define SSL_METHOD_QUAL const -#else -#define SSL_METHOD_QUAL -#endif - -/* - * Number of bytes to read from the random number seed file. This must be - * a finite value (because some entropy "files" like /dev/urandom have - * an infinite length), but must be large enough to provide enough - * entopy to properly seed OpenSSL's PRNG. - */ -#define RAND_LOAD_LENGTH 1024 - -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK -static char global_passwd[64]; -#endif - -static int passwd_callback(char *buf, int num, int verify -#if HAVE_USERDATA_IN_PWD_CALLBACK - /* This was introduced in 0.9.4, we can set this - using SSL_CTX_set_default_passwd_cb_userdata() - */ - , void *global_passwd -#endif - ) -{ - if(verify) - fprintf(stderr, "%s\n", buf); - else { - if(num > (int)strlen((char *)global_passwd)) { - strcpy(buf, global_passwd); - return (int)strlen(buf); - } - } - return 0; -} - -/* - * rand_enough() is a function that returns TRUE if we have seeded the random - * engine properly. We use some preprocessor magic to provide a seed_enough() - * macro to use, just to prevent a compiler warning on this function if we - * pass in an argument that is never used. - */ - -#ifdef HAVE_RAND_STATUS -#define seed_enough(x) rand_enough() -static bool rand_enough(void) -{ - return (bool)(0 != RAND_status()); -} -#else -#define seed_enough(x) rand_enough(x) -static bool rand_enough(int nread) -{ - /* this is a very silly decision to make */ - return (bool)(nread > 500); -} -#endif - -static int ossl_seed(struct SessionHandle *data) -{ - char *buf = data->state.buffer; /* point to the big buffer */ - int nread=0; - - /* Q: should we add support for a random file name as a libcurl option? - A: Yes, it is here */ - -#ifndef RANDOM_FILE - /* if RANDOM_FILE isn't defined, we only perform this if an option tells - us to! */ - if(data->set.ssl.random_file) -#define RANDOM_FILE "" /* doesn't matter won't be used */ -#endif - { - /* let the option override the define */ - nread += RAND_load_file((data->set.ssl.random_file? - data->set.ssl.random_file:RANDOM_FILE), - RAND_LOAD_LENGTH); - if(seed_enough(nread)) - return nread; - } - -#if defined(HAVE_RAND_EGD) - /* only available in OpenSSL 0.9.5 and later */ - /* EGD_SOCKET is set at configure time or not at all */ -#ifndef EGD_SOCKET - /* If we don't have the define set, we only do this if the egd-option - is set */ - if(data->set.ssl.egdsocket) -#define EGD_SOCKET "" /* doesn't matter won't be used */ -#endif - { - /* If there's an option and a define, the option overrides the - define */ - int ret = RAND_egd(data->set.ssl.egdsocket? - data->set.ssl.egdsocket:EGD_SOCKET); - if(-1 != ret) { - nread += ret; - if(seed_enough(nread)) - return nread; - } - } -#endif - - /* If we get here, it means we need to seed the PRNG using a "silly" - approach! */ -#ifdef HAVE_RAND_SCREEN - /* This one gets a random value by reading the currently shown screen */ - RAND_screen(); - nread = 100; /* just a value */ -#else - { - int len; - char *area; - - /* Changed call to RAND_seed to use the underlying RAND_add implementation - * directly. Do this in a loop, with the amount of additional entropy - * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes - * of a 7-bit ascii set. -- Richard Gorton, March 11 2003. - */ - - do { - area = Curl_FormBoundary(); - if(!area) - return 3; /* out of memory */ - - len = (int)strlen(area); - RAND_add(area, len, (len >> 1)); - - free(area); /* now remove the random junk */ - } while (!RAND_status()); - } -#endif - - /* generates a default path for the random seed file */ - buf[0]=0; /* blank it first */ - RAND_file_name(buf, BUFSIZE); - if(buf[0]) { - /* we got a file name to try */ - nread += RAND_load_file(buf, RAND_LOAD_LENGTH); - if(seed_enough(nread)) - return nread; - } - - infof(data, "libcurl is now using a weak random seed!\n"); - return nread; -} - -int Curl_ossl_seed(struct SessionHandle *data) -{ - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; - - if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { - ossl_seed(data); - ssl_seeded = TRUE; - } - return 0; -} - - -#ifndef SSL_FILETYPE_ENGINE -#define SSL_FILETYPE_ENGINE 42 -#endif -#ifndef SSL_FILETYPE_PKCS12 -#define SSL_FILETYPE_PKCS12 43 -#endif -static int do_file_type(const char *type) -{ - if(!type || !type[0]) - return SSL_FILETYPE_PEM; - if(curl_strequal(type, "PEM")) - return SSL_FILETYPE_PEM; - if(curl_strequal(type, "DER")) - return SSL_FILETYPE_ASN1; - if(curl_strequal(type, "ENG")) - return SSL_FILETYPE_ENGINE; - if(curl_strequal(type, "P12")) - return SSL_FILETYPE_PKCS12; - return -1; -} - -static -int cert_stuff(struct connectdata *conn, - SSL_CTX* ctx, - char *cert_file, - const char *cert_type, - char *key_file, - const char *key_type) -{ - struct SessionHandle *data = conn->data; - int file_type; - - if(cert_file != NULL) { - SSL *ssl; - X509 *x509; - int cert_done = 0; - - if(data->set.key_passwd) { -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK - /* - * If password has been given, we store that in the global - * area (*shudder*) for a while: - */ - size_t len = strlen(data->set.key_passwd); - if(len < sizeof(global_passwd)) - memcpy(global_passwd, data->set.key_passwd, len+1); -#else - /* - * We set the password in the callback userdata - */ - SSL_CTX_set_default_passwd_cb_userdata(ctx, - data->set.key_passwd); -#endif - /* Set passwd callback: */ - SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); - } - - file_type = do_file_type(cert_type); - -#define SSL_CLIENT_CERT_ERR \ - "unable to use client certificate (no key found or wrong pass phrase?)" - - switch(file_type) { - case SSL_FILETYPE_PEM: - /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ - if(SSL_CTX_use_certificate_chain_file(ctx, - cert_file) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); - return 0; - } - break; - - case SSL_FILETYPE_ASN1: - /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but - we use the case above for PEM so this can only be performed with - ASN1 files. */ - if(SSL_CTX_use_certificate_file(ctx, - cert_file, - file_type) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); - return 0; - } - break; - case SSL_FILETYPE_ENGINE: - failf(data, "file type ENG for certificate not implemented"); - return 0; - - case SSL_FILETYPE_PKCS12: - { -#ifdef HAVE_PKCS12_SUPPORT - FILE *f; - PKCS12 *p12; - EVP_PKEY *pri; - - f = fopen(cert_file,"rb"); - if (!f) { - failf(data, "could not open PKCS12 file '%s'", cert_file); - return 0; - } - p12 = d2i_PKCS12_fp(f, NULL); - fclose(f); - - PKCS12_PBE_add(); - - if (!PKCS12_parse(p12, data->set.key_passwd, &pri, &x509, NULL)) { - failf(data, - "could not parse PKCS12 file, check password, OpenSSL error %s", - ERR_error_string(ERR_get_error(), NULL) ); - return 0; - } - - PKCS12_free(p12); - - if(SSL_CTX_use_certificate(ctx, x509) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; - } - - if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { - failf(data, "unable to use private key from PKCS12 file '%s'", - cert_file); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; - } - - EVP_PKEY_free(pri); - X509_free(x509); - cert_done = 1; - break; -#else - failf(data, "file type P12 for certificate not supported"); - return 0; -#endif - } - default: - failf(data, "not supported file type '%s' for certificate", cert_type); - return 0; - } - - file_type = do_file_type(key_type); - - switch(file_type) { - case SSL_FILETYPE_PEM: - if(cert_done) - break; - if(key_file == NULL) - /* cert & key can only be in PEM case in the same file */ - key_file=cert_file; - case SSL_FILETYPE_ASN1: - if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { - failf(data, "unable to set private key file: '%s' type %s\n", - key_file, key_type?key_type:"PEM"); - return 0; - } - break; - case SSL_FILETYPE_ENGINE: -#ifdef HAVE_OPENSSL_ENGINE_H - { /* XXXX still needs some work */ - EVP_PKEY *priv_key = NULL; - if(conn && conn->data && conn->data->state.engine) { -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS - UI_METHOD *ui_method = UI_OpenSSL(); -#endif - if(!key_file || !key_file[0]) { - failf(data, "no key set to load from crypto engine\n"); - return 0; - } - /* the typecast below was added to please MinGW32 */ - priv_key = (EVP_PKEY *) - ENGINE_load_private_key(conn->data->state.engine,key_file, -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS - ui_method, -#endif - data->set.key_passwd); - if(!priv_key) { - failf(data, "failed to load private key from crypto engine\n"); - return 0; - } - if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { - failf(data, "unable to set private key\n"); - EVP_PKEY_free(priv_key); - return 0; - } - EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ - } - else { - failf(data, "crypto engine not set, can't load private key\n"); - return 0; - } - } - break; -#else - failf(data, "file type ENG for private key not supported\n"); - return 0; -#endif - case SSL_FILETYPE_PKCS12: - if(!cert_done) { - failf(data, "file type P12 for private key not supported\n"); - return 0; - } - break; - default: - failf(data, "not supported file type for private key\n"); - return 0; - } - - ssl=SSL_new(ctx); - if (NULL == ssl) { - failf(data,"unable to create an SSL structure\n"); - return 0; - } - - x509=SSL_get_certificate(ssl); - - /* This version was provided by Evan Jordan and is supposed to not - leak memory as the previous version: */ - if(x509 != NULL) { - EVP_PKEY *pktmp = X509_get_pubkey(x509); - EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl)); - EVP_PKEY_free(pktmp); - } - - SSL_free(ssl); - - /* If we are using DSA, we can copy the parameters from - * the private key */ - - - /* Now we know that a key and cert have been set against - * the SSL context */ - if(!SSL_CTX_check_private_key(ctx)) { - failf(data, "Private key does not match the certificate public key"); - return(0); - } -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK - /* erase it now */ - memset(global_passwd, 0, sizeof(global_passwd)); -#endif - } - return(1); -} - -static -int cert_verify_callback(int ok, X509_STORE_CTX *ctx) -{ - X509 *err_cert; - char buf[256]; - - err_cert=X509_STORE_CTX_get_current_cert(ctx); - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - return ok; -} - -/* Return error string for last OpenSSL error - */ -static char *SSL_strerror(unsigned long error, char *buf, size_t size) -{ -#ifdef HAVE_ERR_ERROR_STRING_N - /* OpenSSL 0.9.6 and later has a function named - ERRO_error_string_n() that takes the size of the buffer as a - third argument */ - ERR_error_string_n(error, buf, size); -#else - (void) size; - ERR_error_string(error, buf); -#endif - return (buf); -} - -#endif /* USE_SSLEAY */ - -#ifdef USE_SSLEAY -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -int Curl_ossl_init(void) -{ -#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES - ENGINE_load_builtin_engines(); -#endif - - /* Lets get nice error messages */ - SSL_load_error_strings(); - - /* Setup all the global SSL stuff */ - if (!SSLeay_add_ssl_algorithms()) - return 0; - - return 1; -} - -#endif /* USE_SSLEAY */ - -#ifdef USE_SSLEAY - -/* Global cleanup */ -void Curl_ossl_cleanup(void) -{ - /* Free the SSL error strings */ - ERR_free_strings(); - - /* EVP_cleanup() removes all ciphers and digests from the - table. */ - EVP_cleanup(); - -#ifdef HAVE_ENGINE_cleanup - ENGINE_cleanup(); -#endif - -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - /* this function was not present in 0.9.6b, but was added sometimes - later */ - CRYPTO_cleanup_all_ex_data(); -#endif -} - -/* - * This function uses SSL_peek to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -int Curl_ossl_check_cxn(struct connectdata *conn) -{ - int rc; - char buf; - - rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1); - if (rc > 0) - return 1; /* connection still in place */ - - if (rc == 0) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - -#endif /* USE_SSLEAY */ - -/* Selects an OpenSSL crypto engine - */ -CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) -{ -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *e = ENGINE_by_id(engine); - - if (!e) { - failf(data, "SSL Engine '%s' not found", engine); - return (CURLE_SSL_ENGINE_NOTFOUND); - } - - if (data->state.engine) { - ENGINE_finish(data->state.engine); - ENGINE_free(data->state.engine); - data->state.engine = NULL; - } - if (!ENGINE_init(e)) { - char buf[256]; - - ENGINE_free(e); - failf(data, "Failed to initialise SSL Engine '%s':\n%s", - engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf))); - return (CURLE_SSL_ENGINE_INITFAILED); - } - data->state.engine = e; - return (CURLE_OK); -#else - (void)engine; - failf(data, "SSL Engine not supported"); - return (CURLE_SSL_ENGINE_NOTFOUND); -#endif -} - -#ifdef USE_SSLEAY -/* Sets engine as default for all SSL operations - */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) -{ -#ifdef HAVE_OPENSSL_ENGINE_H - if (data->state.engine) { - if (ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { - infof(data,"set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine)); - } - else { - failf(data, "set default crypto engine '%s' failed", ENGINE_get_id(data->state.engine)); - return CURLE_SSL_ENGINE_SETFAILED; - } - } -#else - (void) data; -#endif - return CURLE_OK; -} -#endif /* USE_SSLEAY */ - -/* Return list of OpenSSL crypto engine names. - */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) -{ - struct curl_slist *list = NULL; -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *e; - - for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) - list = curl_slist_append(list, ENGINE_get_id(e)); -#endif - (void) data; - return (list); -} - - -#ifdef USE_SSLEAY - -/* - * This function is called when an SSL connection is closed. - */ -void Curl_ossl_close(struct connectdata *conn) -{ - int i; - /* - ERR_remove_state() frees the error queue associated with - thread pid. If pid == 0, the current thread will have its - error queue removed. - - Since error queue data structures are allocated - automatically for new threads, they must be freed when - threads are terminated in oder to avoid memory leaks. - */ - ERR_remove_state(0); - - for(i=0; i<2; i++) { - struct ssl_connect_data *connssl = &conn->ssl[i]; - - if(connssl->handle) { - (void)SSL_shutdown(connssl->handle); - SSL_set_connect_state(connssl->handle); - - SSL_free (connssl->handle); - connssl->handle = NULL; - } - if(connssl->ctx) { - SSL_CTX_free (connssl->ctx); - connssl->ctx = NULL; - } - connssl->use = FALSE; /* get back to ordinary socket usage */ - } -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) -{ - int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - char buf[120]; /* We will use this for the OpenSSL error buffer, so it has - to be at least 120 bytes long. */ - unsigned long sslerror; - ssize_t nread; - int err; - int done = 0; - - /* 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(connssl->handle) { - while(!done) { - int what = Curl_select(conn->sock[sockindex], - CURL_SOCKET_BAD, 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 */ - nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf, - sizeof(buf)); - err = SSL_get_error(conn->ssl[sockindex].handle, (int)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 = 1; - break; - case SSL_ERROR_WANT_READ: - /* there's data pending, re-invoke SSL_read() */ - infof(data, "SSL_ERROR_WANT_READ\n"); - break; - case SSL_ERROR_WANT_WRITE: - /* SSL wants a write. Really odd. Let's bail out. */ - infof(data, "SSL_ERROR_WANT_WRITE\n"); - done = 1; - break; - default: - /* openssl/ssl.h says "look at error stack/return value/errno" */ - sslerror = ERR_get_error(); - failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, buf), - Curl_sockerrno() ); - done = 1; - break; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - done = 1; - break; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); - retval = -1; - done = 1; - } - } /* while()-loop for the select() */ - - if(data->set.verbose) { - switch(SSL_get_shutdown(connssl->handle)) { - case SSL_SENT_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); - break; - case SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); - break; - case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" - "SSL_RECEIVED__SHUTDOWN\n"); - break; - } - } - - connssl->use = FALSE; /* get back to ordinary socket usage */ - - SSL_free (connssl->handle); - connssl->handle = NULL; - } - return retval; -} - -void Curl_ossl_session_free(void *ptr) -{ - /* free the ID */ - SSL_SESSION_free(ptr); -} - -/* - * This function is called when the 'data' struct is going away. Close - * down everything and free all resources! - */ -int Curl_ossl_close_all(struct SessionHandle *data) -{ -#ifdef HAVE_OPENSSL_ENGINE_H - if(data->state.engine) { - ENGINE_finish(data->state.engine); - ENGINE_free(data->state.engine); - data->state.engine = NULL; - } -#else - (void)data; -#endif - return 0; -} - -static int Curl_ASN1_UTCTIME_output(struct connectdata *conn, - const char *prefix, - ASN1_UTCTIME *tm) -{ - char *asn1_string; - int gmt=FALSE; - int i; - int year=0,month=0,day=0,hour=0,minute=0,second=0; - struct SessionHandle *data = conn->data; - - if(!data->set.verbose) - return 0; - - i=tm->length; - asn1_string=(char *)tm->data; - - if(i < 10) - return 1; - if(asn1_string[i-1] == 'Z') - gmt=TRUE; - for (i=0; i<10; i++) - if((asn1_string[i] > '9') || (asn1_string[i] < '0')) - return 2; - - year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0'); - if(year < 50) - year+=100; - - month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0'); - if((month > 12) || (month < 1)) - return 3; - - day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0'); - hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0'); - minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0'); - - if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') && - (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) - second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0'); - - infof(data, - "%s%04d-%02d-%02d %02d:%02d:%02d %s\n", - prefix, year+1900, month, day, hour, minute, second, (gmt?"GMT":"")); - - return 0; -} - -#endif - -/* ====================================================== */ -#ifdef USE_SSLEAY - -/* - * Match a hostname against a wildcard pattern. - * E.g. - * "foo.host.com" matches "*.host.com". - * - * We are a bit more liberal than RFC2818 describes in that we - * accept multiple "*" in pattern (similar to what some other browsers do). - * E.g. - * "abc.def.domain.com" should strickly not match "*.domain.com", but we - * don't consider "." to be important in CERT checking. - */ -#define HOST_NOMATCH 0 -#define HOST_MATCH 1 - -static int hostmatch(const char *hostname, const char *pattern) -{ - while (1) { - int c = *pattern++; - - if (c == '\0') - return (*hostname ? HOST_NOMATCH : HOST_MATCH); - - if (c == '*') { - c = *pattern; - if (c == '\0') /* "*\0" matches anything remaining */ - return HOST_MATCH; - - while (*hostname) { - /* The only recursive function in libcurl! */ - if (hostmatch(hostname++,pattern) == HOST_MATCH) - return HOST_MATCH; - } - break; - } - - if (toupper(c) != toupper(*hostname++)) - break; - } - return HOST_NOMATCH; -} - -static int -cert_hostcheck(const char *match_pattern, const char *hostname) -{ - if (!match_pattern || !*match_pattern || - !hostname || !*hostname) /* sanity check */ - return 0; - - if(curl_strequal(hostname,match_pattern)) /* trivial case */ - return 1; - - if (hostmatch(hostname,match_pattern) == HOST_MATCH) - return 1; - return 0; -} - -/* Quote from RFC2818 section 3.1 "Server Identity" - - If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. Otherwise, the (most specific) Common Name - field in the Subject field of the certificate MUST be used. Although - the use of the Common Name is existing practice, it is deprecated and - 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 - 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 - component or component fragment. E.g., *.a.com matches foo.a.com but - not bar.foo.a.com. f*.com matches foo.com but not bar.com. - - In some cases, the URI is specified as an IP address rather than a - hostname. In this case, the iPAddress subjectAltName must be present - in the certificate and must exactly match the IP in the URI. - -*/ -static CURLcode verifyhost(struct connectdata *conn, - X509 *server_cert) -{ - bool matched = FALSE; /* no alternative match yet */ - int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ - int addrlen = 0; - struct SessionHandle *data = conn->data; - STACK_OF(GENERAL_NAME) *altnames; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - CURLcode res = CURLE_OK; - -#ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, conn->host.name, &addr)) { - target = GEN_IPADD; - addrlen = sizeof(struct in6_addr); - } - else -#endif - if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) { - target = GEN_IPADD; - addrlen = sizeof(struct in_addr); - } - - /* get a "list" of alternative names */ - altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); - - if(altnames) { - int numalts; - int i; - - /* get amount of alternatives, RFC2459 claims there MUST be at least - one, but we don't depend on it... */ - numalts = sk_GENERAL_NAME_num(altnames); - - /* loop through all alternatives while none has matched */ - for (i=0; (itype == target) { - /* get data and length */ - const char *altptr = (char *)ASN1_STRING_data(check->d.ia5); - int altlen; - - switch(target) { - case GEN_DNS: /* name/pattern comparison */ - /* 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 - type itself: for example for and IA5String the data will be ASCII" - - Gisle researched the OpenSSL sources: - "I checked the 0.9.6 and 0.9.8 sources before my patch and - it always 0-terminates an IA5String." - */ - if (cert_hostcheck(altptr, conn->host.name)) - matched = TRUE; - break; - - case GEN_IPADD: /* IP address comparison */ - /* compare alternative IP address if the data chunk is the same size - our server IP address is */ - altlen = ASN1_STRING_length(check->d.ia5); - if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) - matched = TRUE; - break; - } - } - } - GENERAL_NAMES_free(altnames); - } - - if(matched) - /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); - else { - /* we have to look to the last occurence of a commonName in the - distinguished one to get the most significant one. */ - int j,i=-1 ; - -/* The following is done because of a bug in 0.9.6b */ - - unsigned char *nulstr = (unsigned char *)""; - unsigned char *peer_CN = nulstr; - - X509_NAME *name = X509_get_subject_name(server_cert) ; - if (name) - while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0) - i=j; - - /* we have the name entry and we will now convert this to a string - that we can use for comparison. Doing this we support BMPstring, - UTF8 etc. */ - - if (i>=0) { - ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); - - /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input - is already UTF-8 encoded. We check for this case and copy the raw - string manually to avoid the problem. This code can be made - conditional in the future when OpenSSL has been fixed. Work-around - brought by Alexis S. L. Carvalho. */ - if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { - j = ASN1_STRING_length(tmp); - if (j >= 0) { - peer_CN = OPENSSL_malloc(j+1); - if (peer_CN) { - memcpy(peer_CN, ASN1_STRING_data(tmp), j); - peer_CN[j] = '\0'; - } - } - } - else /* not a UTF8 name */ - j = ASN1_STRING_to_UTF8(&peer_CN, tmp); - } - - if (peer_CN == nulstr) - peer_CN = NULL; -#ifdef CURL_DOES_CONVERSIONS - else { - /* convert peer_CN from UTF8 */ - size_t rc; - rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN)); - /* Curl_convert_from_utf8 calls failf if unsuccessful */ - if (rc != CURLE_OK) { - return(rc); - } - } -#endif /* CURL_DOES_CONVERSIONS */ - - if (!peer_CN) { - if(data->set.ssl.verifyhost > 1) { - failf(data, - "SSL: unable to obtain common name from peer certificate"); - return CURLE_SSL_PEER_CERTIFICATE; - } - else { - /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we - output a note about the situation */ - infof(data, "\t common name: WARNING couldn't obtain\n"); - } - } - else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) { - if(data->set.ssl.verifyhost > 1) { - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, conn->host.dispname); - res = CURLE_SSL_PEER_CERTIFICATE; - } - else - infof(data, "\t common name: %s (does not match '%s')\n", - peer_CN, conn->host.dispname); - } - else { - infof(data, "\t common name: %s (matched)\n", peer_CN); - } - if(peer_CN) - OPENSSL_free(peer_CN); - } - return res; -} -#endif - -/* 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 - -static const char *ssl_msg_type(int ssl_ver, int msg) -{ - if (ssl_ver == SSL2_VERSION_MAJOR) { - switch (msg) { - case SSL2_MT_ERROR: - return "Error"; - case SSL2_MT_CLIENT_HELLO: - return "Client hello"; - case SSL2_MT_CLIENT_MASTER_KEY: - return "Client key"; - case SSL2_MT_CLIENT_FINISHED: - return "Client finished"; - case SSL2_MT_SERVER_HELLO: - return "Server hello"; - case SSL2_MT_SERVER_VERIFY: - return "Server verify"; - case SSL2_MT_SERVER_FINISHED: - return "Server finished"; - case SSL2_MT_REQUEST_CERTIFICATE: - return "Request CERT"; - case SSL2_MT_CLIENT_CERTIFICATE: - return "Client CERT"; - } - } - else if (ssl_ver == SSL3_VERSION_MAJOR) { - switch (msg) { - case SSL3_MT_HELLO_REQUEST: - return "Hello request"; - case SSL3_MT_CLIENT_HELLO: - return "Client hello"; - case SSL3_MT_SERVER_HELLO: - return "Server hello"; - case SSL3_MT_CERTIFICATE: - return "CERT"; - case SSL3_MT_SERVER_KEY_EXCHANGE: - return "Server key exchange"; - case SSL3_MT_CLIENT_KEY_EXCHANGE: - return "Client key exchange"; - case SSL3_MT_CERTIFICATE_REQUEST: - return "Request CERT"; - case SSL3_MT_SERVER_DONE: - return "Server finished"; - case SSL3_MT_CERTIFICATE_VERIFY: - return "CERT verify"; - case SSL3_MT_FINISHED: - return "Finished"; - } - } - return "Unknown"; -} - -static const char *tls_rt_type(int type) -{ - return ( - type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " : - type == SSL3_RT_ALERT ? "TLS alert, " : - type == SSL3_RT_HANDSHAKE ? "TLS handshake, " : - type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " : - "TLS Unknown, "); -} - - -/* - * Our callback from the SSL/TLS layers. - */ -static void ssl_tls_trace(int direction, int ssl_ver, int content_type, - const void *buf, size_t len, const SSL *ssl, - struct connectdata *conn) -{ - struct SessionHandle *data; - const char *msg_name, *tls_rt_name; - char ssl_buf[1024]; - int ver, msg_type, txt_len; - - if (!conn || !conn->data || !conn->data->set.fdebug || - (direction != 0 && direction != 1)) - return; - - data = conn->data; - ssl_ver >>= 8; - ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' : - ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?'); - - /* 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]'. - */ - if (ssl_ver == SSL3_VERSION_MAJOR && content_type != 0) - tls_rt_name = tls_rt_type(content_type); - else - tls_rt_name = ""; - - msg_type = *(char*)buf; - msg_name = ssl_msg_type(ssl_ver, msg_type); - - txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n", - ver, tls_rt_name, msg_name, msg_type); - Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); - - Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : - CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL); - (void) ssl; -} -#endif - -#ifdef USE_SSLEAY -/* ====================================================== */ - -static CURLcode -Curl_ossl_connect_step1(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode = CURLE_OK; - - struct SessionHandle *data = conn->data; - SSL_METHOD_QUAL SSL_METHOD *req_method=NULL; - void *ssl_sessionid=NULL; - curl_socket_t sockfd = conn->sock[sockindex]; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - curlassert(ssl_connect_1 == connssl->connecting_state); - - /* Make funny stuff to get random input */ - Curl_ossl_seed(data); - - /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { - default: - case CURL_SSLVERSION_DEFAULT: - /* we try to figure out version */ - req_method = SSLv23_client_method(); - break; - case CURL_SSLVERSION_TLSv1: - req_method = TLSv1_client_method(); - break; - case CURL_SSLVERSION_SSLv2: -#ifdef OPENSSL_NO_SSL2 - failf(data, "OpenSSL was built without SSLv2 support"); - return CURLE_NOT_BUILT_IN; -#else - req_method = SSLv2_client_method(); - break; -#endif - case CURL_SSLVERSION_SSLv3: - req_method = SSLv3_client_method(); - break; - } - - if (connssl->ctx) - SSL_CTX_free(connssl->ctx); - connssl->ctx = SSL_CTX_new(req_method); - - if(!connssl->ctx) { - failf(data, "SSL: couldn't create a context!"); - return CURLE_OUT_OF_MEMORY; - } - -#ifdef SSL_CTRL_SET_MSG_CALLBACK - if (data->set.fdebug && data->set.verbose) { - /* the SSL trace callback is only used for verbose logging so we only - inform about failures of setting it */ - if (!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK, - (void (*)(void))ssl_tls_trace)) { - infof(data, "SSL: couldn't set callback!\n"); - } - else if (!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, - conn)) { - infof(data, "SSL: couldn't set callback argument!\n"); - } - } -#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 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." - - */ - SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL); - -#if 0 - /* - * Not sure it's needed to tell SSL_connect() that socket is - * non-blocking. It doesn't seem to care, but just return with - * SSL_ERROR_WANT_x. - */ - if (data->state.used_interface == Curl_if_multi) - SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL); -#endif - - if(data->set.cert) { - if(!cert_stuff(conn, - connssl->ctx, - data->set.cert, - data->set.cert_type, - data->set.key, - data->set.key_type)) { - /* failf() is already done in cert_stuff() */ - return CURLE_SSL_CERTPROBLEM; - } - } - - if(data->set.ssl.cipher_list) { - if(!SSL_CTX_set_cipher_list(connssl->ctx, - data->set.ssl.cipher_list)) { - failf(data, "failed setting cipher list"); - return CURLE_SSL_CIPHER; - } - } - - if (data->set.ssl.CAfile || data->set.ssl.CApath) { - /* tell SSL where to find CA certificates that are used to verify - the servers certificate. */ - if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile, - data->set.ssl.CApath)) { - if (data->set.ssl.verifypeer) { - /* Fail if we insist on successfully verifying the server. */ - failf(data,"error setting certificate verify locations:\n" - " CAfile: %s\n CApath: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", - data->set.ssl.CApath ? data->set.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:\n"); - } - } - else { - /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:\n"); - } - infof(data, - " CAfile: %s\n" - " CApath: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); - } - /* SSL 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(connssl->ctx, - data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, - cert_verify_callback); - - /* give application a chance to interfere with SSL set up. */ - if(data->set.ssl.fsslctx) { - retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx, - data->set.ssl.fsslctxp); - if(retcode) { - failf(data,"error signaled by ssl ctx callback"); - return retcode; - } - } - - /* Lets make an SSL structure */ - if (connssl->handle) - SSL_free(connssl->handle); - connssl->handle = SSL_new(connssl->ctx); - if (!connssl->handle) { - failf(data, "SSL: couldn't create a context (handle)!"); - return CURLE_OUT_OF_MEMORY; - } - SSL_set_connect_state(connssl->handle); - - connssl->server_cert = 0x0; - - /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* we got a session id, use it! */ - if (!SSL_set_session(connssl->handle, ssl_sessionid)) { - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(ERR_get_error(),NULL)); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); - } - - /* pass the raw socket into the SSL layers */ - if (!SSL_set_fd(connssl->handle, sockfd)) { - failf(data, "SSL: SSL_set_fd failed: %s", - ERR_error_string(ERR_get_error(),NULL)); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->connecting_state = ssl_connect_2; - return CURLE_OK; -} - -static CURLcode -Curl_ossl_connect_step2(struct connectdata *conn, - int sockindex, long *timeout_ms) -{ - struct SessionHandle *data = conn->data; - int err; - long has_passed; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - curlassert(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); - - /* Find out if any timeout is set. If not, use 300 seconds. - Otherwise, figure out the most strict timeout of the two possible one - and then how much time that has elapsed to know how much time we - allow for the connect call */ - if(data->set.timeout && data->set.connecttimeout) { - /* get the most strict timeout of the ones converted to milliseconds */ - if(data->set.timeoutset.connecttimeout) - *timeout_ms = data->set.timeout*1000; - else - *timeout_ms = data->set.connecttimeout*1000; - } - else if(data->set.timeout) - *timeout_ms = data->set.timeout*1000; - else if(data->set.connecttimeout) - *timeout_ms = data->set.connecttimeout*1000; - else - /* no particular time-out has been set */ - *timeout_ms= DEFAULT_CONNECT_TIMEOUT; - - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - - /* subtract the passed time */ - *timeout_ms -= has_passed; - - if(*timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEOUTED; - } - - err = SSL_connect(connssl->handle); - - /* 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(connssl->handle, err); - - if(SSL_ERROR_WANT_READ == detail) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - else if(SSL_ERROR_WANT_WRITE == detail) { - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - } - else { - /* untreated error */ - unsigned long errdetail; - char error_buffer[256]; /* OpenSSL documents that this must be at least - 256 bytes long. */ - CURLcode rc; - const char *cert_problem = NULL; - - connssl->connecting_state = ssl_connect_2; /* the connection failed, - we're not waiting for - anything else. */ - - errdetail = ERR_get_error(); /* Gets the earliest error code from the - thread's error queue and removes the - entry. */ - - switch(errdetail) { - case 0x1407E086: - /* 1407E086: - SSL routines: - SSL2_SET_CERTIFICATE: - certificate verify failed */ - /* fall-through */ - case 0x14090086: - /* 14090086: - SSL routines: - SSL3_GET_SERVER_CERTIFICATE: - certificate verify failed */ - cert_problem = "SSL certificate problem, verify that the CA cert is" - " OK. Details:\n"; - rc = CURLE_SSL_CACERT; - break; - default: - rc = CURLE_SSL_CONNECT_ERROR; - break; - } - - /* detail is already set to the SSL error above */ - - /* 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. - */ - if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) { - failf(data, "Unknown SSL protocol error in connection to %s:%d ", - conn->host.name, conn->port); - return rc; - } - /* Could be a CERT problem */ - - SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); - failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); - return rc; - } - } - else { - /* we have been connected fine, we're not waiting for anything else. */ - connssl->connecting_state = ssl_connect_3; - - /* Informational message */ - infof (data, "SSL connection using %s\n", - SSL_get_cipher(connssl->handle)); - - return CURLE_OK; - } -} - -static CURLcode -Curl_ossl_connect_step3(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode = CURLE_OK; - char * str; - long lerr; - ASN1_TIME *certdate; - void *ssl_sessionid=NULL; - struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - curlassert(ssl_connect_3 == connssl->connecting_state); - - if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* Since this is not a cached session ID, then we want to stach this one - in the cache! */ - SSL_SESSION *our_ssl_sessionid; -#ifdef HAVE_SSL_GET1_SESSION - our_ssl_sessionid = SSL_get1_session(connssl->handle); - - /* SSL_get1_session() will increment the reference - count and the session will stay in memory until explicitly freed with - SSL_SESSION_free(3), regardless of its state. - This function was introduced in openssl 0.9.5a. */ -#else - our_ssl_sessionid = SSL_get_session(connssl->handle); - - /* if SSL_get1_session() is unavailable, use SSL_get_session(). - This is an inferior option because the session can be flushed - at any time by openssl. It is included only so curl compiles - under versions of openssl < 0.9.5a. - - WARNING: How curl behaves if it's session is flushed is - untested. - */ -#endif - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(retcode) { - failf(data, "failed to store ssl session"); - return retcode; - } - } - - - /* Get server's certificate (note: beware of dynamic allocation) - opt */ - /* major serious hack alert -- we should check certificates - * to authenticate the server; otherwise we risk man-in-the-middle - * attack - */ - - connssl->server_cert = SSL_get_peer_certificate(connssl->handle); - if(!connssl->server_cert) { - failf(data, "SSL: couldn't get peer certificate!"); - return CURLE_SSL_PEER_CERTIFICATE; - } - infof (data, "Server certificate:\n"); - - str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert), - NULL, 0); - if(!str) { - failf(data, "SSL: couldn't get X509-subject!"); - X509_free(connssl->server_cert); - connssl->server_cert = NULL; - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "\t subject: %s\n", str); - CRYPTO_free(str); - - certdate = X509_get_notBefore(connssl->server_cert); - Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); - - certdate = X509_get_notAfter(connssl->server_cert); - Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); - - if(data->set.ssl.verifyhost) { - retcode = verifyhost(conn, connssl->server_cert); - if(retcode) { - X509_free(connssl->server_cert); - connssl->server_cert = NULL; - return retcode; - } - } - - str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert), - NULL, 0); - if(!str) { - failf(data, "SSL: couldn't get X509-issuer name!"); - retcode = CURLE_SSL_CONNECT_ERROR; - } - else { - infof(data, "\t issuer: %s\n", str); - CRYPTO_free(str); - - /* We could do all sorts of certificate verification stuff here before - deallocating the certificate. */ - - lerr = data->set.ssl.certverifyresult= - SSL_get_verify_result(connssl->handle); - if(data->set.ssl.certverifyresult != X509_V_OK) { - if(data->set.ssl.verifypeer) { - /* We probably never reach this, because SSL_connect() will fail - and we return earlyer if verifypeer is set? */ - failf(data, "SSL certificate verify result: %s (%ld)", - X509_verify_cert_error_string(lerr), lerr); - retcode = CURLE_SSL_PEER_CERTIFICATE; - } - else - infof(data, "SSL certificate verify result: %s (%ld)," - " continuing anyway.\n", - X509_verify_cert_error_string(lerr), lerr); - } - else - infof(data, "SSL certificate verify ok.\n"); - } - - X509_free(connssl->server_cert); - connssl->server_cert = NULL; - connssl->connecting_state = ssl_connect_done; - return retcode; -} - -static CURLcode -Curl_ossl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode retcode; - struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; - - if (ssl_connect_1==connssl->connecting_state) { - retcode = Curl_ossl_connect_step1(conn, sockindex); - if (retcode) - return retcode; - } - - timeout_ms = 0; - while (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* 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 writefd = ssl_connect_2_writing== - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - int readfd = ssl_connect_2_reading== - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - while(1) { - int what = Curl_select(readfd, writefd, nonblocking?0:(int)timeout_ms); - if(what > 0) - /* readable or writable, go loop in the outer loop */ - break; - else if(0 == what) { - if (nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); - return CURLE_SSL_CONNECT_ERROR; - } - } /* while()-loop for the select() */ - } - - /* get the timeout from step2 to avoid computing it twice. */ - retcode = Curl_ossl_connect_step2(conn, sockindex, &timeout_ms); - if (retcode) - return retcode; - - } /* repeat step2 until all transactions are done. */ - - - if (ssl_connect_3==connssl->connecting_state) { - retcode = Curl_ossl_connect_step3(conn, sockindex); - if (retcode) - return retcode; - } - - if (ssl_connect_done==connssl->connecting_state) { - *done = TRUE; - } - else { - *done = FALSE; - } - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -CURLcode -Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) -{ - return Curl_ossl_connect_common(conn, sockindex, TRUE, done); -} - -CURLcode -Curl_ossl_connect(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode; - bool done = FALSE; - - retcode = Curl_ossl_connect_common(conn, sockindex, FALSE, &done); - if (retcode) - return retcode; - - curlassert(done); - - return CURLE_OK; -} - -/* return number of sent (non-SSL) bytes */ -ssize_t Curl_ossl_send(struct connectdata *conn, - int sockindex, - void *mem, - size_t len) -{ - /* SSL_write() is said to return 'int' while write() and send() returns - 'size_t' */ - int err; - char error_buffer[120]; /* OpenSSL documents that this must be at least 120 - bytes long. */ - unsigned long sslerror; - int rc = SSL_write(conn->ssl[sockindex].handle, mem, (int)len); - - if(rc < 0) { - err = SSL_get_error(conn->ssl[sockindex].handle, rc); - - switch(err) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* The operation did not complete; the same TLS/SSL I/O function - should be called again later. This is basicly an EWOULDBLOCK - equivalent. */ - return 0; - case SSL_ERROR_SYSCALL: - failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n", - Curl_sockerrno()); - return -1; - case SSL_ERROR_SSL: - /* A failure in the SSL library occurred, usually a protocol error. - The OpenSSL error queue contains more information on the error. */ - sslerror = ERR_get_error(); - failf(conn->data, "SSL_write() error: %s\n", - ERR_error_string(sslerror, error_buffer)); - return -1; - } - /* a true error */ - failf(conn->data, "SSL_write() return error %d\n", err); - return -1; - } - return (ssize_t)rc; /* number of bytes */ -} - -/* - * If the read would block we return -1 and set 'wouldblock' to TRUE. - * Otherwise we return the amount of data read. Other errors should return -1 - * and set 'wouldblock' to FALSE. - */ -ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - bool *wouldblock) -{ - char error_buffer[120]; /* OpenSSL documents that this must be at - least 120 bytes long. */ - unsigned long sslerror; - ssize_t nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, - (int)buffersize); - *wouldblock = FALSE; - if(nread < 0) { - /* failed SSL_read */ - int err = SSL_get_error(conn->ssl[num].handle, (int)nread); - - switch(err) { - case SSL_ERROR_NONE: /* this is not an error */ - case SSL_ERROR_ZERO_RETURN: /* no more data */ - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* there's data pending, re-invoke SSL_read() */ - *wouldblock = TRUE; - return -1; /* basically EWOULDBLOCK */ - default: - /* openssl/ssl.h says "look at error stack/return value/errno" */ - sslerror = ERR_get_error(); - failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, error_buffer), - Curl_sockerrno() ); - return -1; - } - } - return nread; -} - -size_t Curl_ossl_version(char *buffer, size_t size) -{ -#ifdef YASSL_VERSION - /* yassl provides an OpenSSL API compatiblity layer so it looks identical - to OpenSSL in all other aspects */ - return snprintf(buffer, size, " yassl/%s", YASSL_VERSION); -#else /* YASSL_VERSION */ - -#if (SSLEAY_VERSION_NUMBER >= 0x905000) - { - char sub[2]; - unsigned long ssleay_value; - sub[1]='\0'; - ssleay_value=SSLeay(); - if(ssleay_value < 0x906000) { - ssleay_value=SSLEAY_VERSION_NUMBER; - sub[0]='\0'; - } - else { - if(ssleay_value&0xff0) { - sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); - } - else - sub[0]='\0'; - } - - return snprintf(buffer, size, " OpenSSL/%lx.%lx.%lx%s", - (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); - } - -#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ - -#if (SSLEAY_VERSION_NUMBER >= 0x900000) - return snprintf(buffer, size, " OpenSSL/%lx.%lx.%lx", - (SSLEAY_VERSION_NUMBER>>28)&0xff, - (SSLEAY_VERSION_NUMBER>>20)&0xff, - (SSLEAY_VERSION_NUMBER>>12)&0xf); - -#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ - { - char sub[2]; - sub[1]='\0'; - if(SSLEAY_VERSION_NUMBER&0x0f) { - sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1; - } - else - sub[0]='\0'; - - return snprintf(buffer, size, " SSL/%x.%x.%x%s", - (SSLEAY_VERSION_NUMBER>>12)&0xff, - (SSLEAY_VERSION_NUMBER>>8)&0xf, - (SSLEAY_VERSION_NUMBER>>4)&0xf, sub); - } -#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ -#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ - -#endif /* YASSL_VERSION */ -} -#endif /* USE_SSLEAY */ diff --git a/Utilities/cmcurl/ssluse.h b/Utilities/cmcurl/ssluse.h deleted file mode 100644 index 5bb7090..0000000 --- a/Utilities/cmcurl/ssluse.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef __SSLUSE_H -#define __SSLUSE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * This header should only be needed to get included by sslgen.c and ssluse.c - */ - -#include "urldata.h" -CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */ -/* tell OpenSSL to close down all open information regarding connections (and - thus session ID caching etc) */ -int Curl_ossl_close_all(struct SessionHandle *data); -/* Sets an OpenSSL engine */ -CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine); - -/* function provided for the generic SSL-layer, called when a session id - should be freed */ -void Curl_ossl_session_free(void *ptr); - -/* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data); - -/* Build list of OpenSSL engines */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data); - -int Curl_ossl_init(void); -void Curl_ossl_cleanup(void); - -ssize_t Curl_ossl_send(struct connectdata *conn, - int sockindex, - void *mem, - size_t len); -ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - bool *wouldblock); - -size_t Curl_ossl_version(char *buffer, size_t size); -int Curl_ossl_check_cxn(struct connectdata *cxn); -int Curl_ossl_seed(struct SessionHandle *data); - -int Curl_ossl_shutdown(struct connectdata *conn, int sockindex); - -#endif diff --git a/Utilities/cmcurl/strdup.c b/Utilities/cmcurl/strdup.c deleted file mode 100644 index e16e08a..0000000 --- a/Utilities/cmcurl/strdup.c +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include "strdup.h" - -#ifndef HAVE_STRDUP -char *curlx_strdup(const char *str) -{ - int len; - char *newstr; - - if (!str) - return (char *)NULL; - - len = strlen(str); - newstr = (char *) malloc((len+1)*sizeof(char)); - if (!newstr) - return (char *)NULL; - - strcpy(newstr,str); - - return newstr; - -} -#endif diff --git a/Utilities/cmcurl/strdup.h b/Utilities/cmcurl/strdup.h deleted file mode 100644 index 3206db3..0000000 --- a/Utilities/cmcurl/strdup.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifndef _CURL_STRDUP_H -#define _CURL_STRDUP_H - -#include "setup.h" - -#ifndef HAVE_STRDUP -extern char *curlx_strdup(const char *str); -#endif - -#endif - diff --git a/Utilities/cmcurl/strequal.c b/Utilities/cmcurl/strequal.c deleted file mode 100644 index 83796f6..0000000 --- a/Utilities/cmcurl/strequal.c +++ /dev/null @@ -1,101 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include -#ifdef HAVE_STRINGS_H -#include -#endif - -#include "strequal.h" - -#if defined(HAVE_STRCASECMP) && defined(__STRICT_ANSI__) -/* this is for "-ansi -Wall -pedantic" to stop complaining! */ -extern int (strcasecmp)(const char *s1, const char *s2); -extern int (strncasecmp)(const char *s1, const char *s2, size_t n); -#endif - -int curl_strequal(const char *first, const char *second) -{ -#if defined(HAVE_STRCASECMP) - return !(strcasecmp)(first, second); -#elif defined(HAVE_STRCMPI) - return !(strcmpi)(first, second); -#elif defined(HAVE_STRICMP) - return !(stricmp)(first, second); -#else - while (*first && *second) { - if (toupper(*first) != toupper(*second)) { - break; - } - first++; - second++; - } - return toupper(*first) == toupper(*second); -#endif -} - -int curl_strnequal(const char *first, const char *second, size_t max) -{ -#if defined(HAVE_STRCASECMP) - return !strncasecmp(first, second, max); -#elif defined(HAVE_STRCMPI) - return !strncmpi(first, second, max); -#elif defined(HAVE_STRICMP) - return !strnicmp(first, second, max); -#else - while (*first && *second && max) { - if (toupper(*first) != toupper(*second)) { - break; - } - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return toupper(*first) == toupper(*second); -#endif -} - -/* - * Curl_strcasestr() finds the first occurrence of the substring needle in the - * string haystack. The terminating `\0' characters are not compared. The - * matching is done CASE INSENSITIVE, which thus is the difference between - * this and strstr(). - */ -char *Curl_strcasestr(const char *haystack, const char *needle) -{ - size_t nlen = strlen(needle); - size_t hlen = strlen(haystack); - - while(hlen-- >= nlen) { - if(curl_strnequal(haystack, needle, nlen)) - return (char *)haystack; - haystack++; - } - return NULL; -} diff --git a/Utilities/cmcurl/strequal.h b/Utilities/cmcurl/strequal.h deleted file mode 100644 index 6718c3c0..0000000 --- a/Utilities/cmcurl/strequal.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __STREQUAL_H -#define __STREQUAL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include - -#define strequal(a,b) curl_strequal(a,b) -#define strnequal(a,b,c) curl_strnequal(a,b,c) - -/* checkprefix() is a shorter version of the above, used when the first - argument is zero-byte terminated */ -#define checkprefix(a,b) strnequal(a,b,strlen(a)) - -/* case insensitive strstr() */ -char *Curl_strcasestr(const char *haystack, const char *needle); - -#endif diff --git a/Utilities/cmcurl/strerror.c b/Utilities/cmcurl/strerror.c deleted file mode 100644 index 74c3457..0000000 --- a/Utilities/cmcurl/strerror.c +++ /dev/null @@ -1,751 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2004 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifdef HAVE_STRERROR_R -#if !defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R) -#error "you MUST have either POSIX or glibc strerror_r if strerror_r is found" -#endif /* !POSIX && !glibc */ -#endif /* HAVE_STRERROR_R */ - -#include -#include -#include -#include - -#ifdef USE_LIBIDN -#include -#endif - -#include "strerror.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(HAVE_STRERROR_R) && defined(HAVE_NO_STRERROR_R_DECL) -#ifdef HAVE_POSIX_STRERROR_R -/* seen on AIX 5100-02 gcc 2.9 */ -extern int strerror_r(int errnum, char *strerrbuf, size_t buflen); -#else -extern char *strerror_r(int errnum, char *buf, size_t buflen); -#endif -#endif - -const char * -curl_easy_strerror(CURLcode error) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (error) { - case CURLE_OK: - return "no error"; - - case CURLE_UNSUPPORTED_PROTOCOL: - return "unsupported protocol"; - - case CURLE_FAILED_INIT: - return "failed init"; - - case CURLE_URL_MALFORMAT: - return "URL using bad/illegal format or missing URL"; - - case CURLE_NOT_BUILT_IN: - return "A requested feature, protocol or option was not found built-in in" - " this libcurl due to a build-time decision."; - - case CURLE_COULDNT_RESOLVE_PROXY: - return "couldn't resolve proxy name"; - - case CURLE_COULDNT_RESOLVE_HOST: - return "couldn't resolve host name"; - - case CURLE_COULDNT_CONNECT: - return "couldn't connect to server"; - - case CURLE_FTP_WEIRD_SERVER_REPLY: - return "FTP: weird server reply"; - - case CURLE_FTP_ACCESS_DENIED: - return "FTP: access denied"; - - case CURLE_FTP_WEIRD_PASS_REPLY: - return "FTP: unknown PASS reply"; - - case CURLE_FTP_WEIRD_USER_REPLY: - return "FTP: unknown USER reply"; - - case CURLE_FTP_WEIRD_PASV_REPLY: - return "FTP: unknown PASV reply"; - - case CURLE_FTP_WEIRD_227_FORMAT: - return "FTP: unknown 227 response format"; - - case CURLE_FTP_CANT_GET_HOST: - return "FTP: can't figure out the host in the PASV response"; - - case CURLE_FTP_CANT_RECONNECT: - return "FTP: can't connect to server the response code is unknown"; - - case CURLE_FTP_COULDNT_SET_BINARY: - return "FTP: couldn't set binary mode"; - - case CURLE_PARTIAL_FILE: - return "Transferred a partial file"; - - case CURLE_FTP_COULDNT_RETR_FILE: - return "FTP: couldn't retrieve (RETR failed) the specified file"; - - case CURLE_FTP_WRITE_ERROR: - return "FTP: the post-transfer acknowledge response was not OK"; - - case CURLE_FTP_QUOTE_ERROR: - return "FTP: a quote command returned error"; - - case CURLE_HTTP_RETURNED_ERROR: - return "HTTP response code said error"; - - case CURLE_WRITE_ERROR: - return "failed writing received data to disk/application"; - - case CURLE_FTP_COULDNT_STOR_FILE: - return "failed FTP upload (the STOR command)"; - - case CURLE_READ_ERROR: - return "failed to open/read local data from file/application"; - - case CURLE_OUT_OF_MEMORY: -#ifdef CURL_DOES_CONVERSIONS - return "conversion failed -or- out of memory"; -#else - return "out of memory"; -#endif /* CURL_DOES_CONVERSIONS */ - - case CURLE_OPERATION_TIMEOUTED: - return "a timeout was reached"; - - case CURLE_FTP_COULDNT_SET_ASCII: - return "FTP could not set ASCII mode (TYPE A)"; - - case CURLE_FTP_PORT_FAILED: - return "FTP command PORT failed"; - - case CURLE_FTP_COULDNT_USE_REST: - return "FTP command REST failed"; - - case CURLE_FTP_COULDNT_GET_SIZE: - return "FTP command SIZE failed"; - - case CURLE_HTTP_RANGE_ERROR: - return "a range was requested but the server did not deliver it"; - - case CURLE_HTTP_POST_ERROR: - return "internal problem setting up the POST"; - - case CURLE_SSL_CONNECT_ERROR: - return "SSL connect error"; - - case CURLE_BAD_DOWNLOAD_RESUME: - return "couldn't resume download"; - - case CURLE_FILE_COULDNT_READ_FILE: - return "couldn't read a file:// file"; - - case CURLE_LDAP_CANNOT_BIND: - return "LDAP: cannot bind"; - - case CURLE_LDAP_SEARCH_FAILED: - return "LDAP: search failed"; - - case CURLE_LIBRARY_NOT_FOUND: - return "a required shared library was not found"; - - case CURLE_FUNCTION_NOT_FOUND: - return "a required function in the shared library was not found"; - - case CURLE_ABORTED_BY_CALLBACK: - return "the operation was aborted by an application callback"; - - case CURLE_BAD_FUNCTION_ARGUMENT: - return "a libcurl function was given a bad argument"; - - case CURLE_INTERFACE_FAILED: - return "failed binding local connection end"; - - case CURLE_TOO_MANY_REDIRECTS : - return "number of redirects hit maximum amount"; - - case CURLE_UNKNOWN_TELNET_OPTION: - return "User specified an unknown option"; - - case CURLE_TELNET_OPTION_SYNTAX : - return "Malformed telnet option"; - - case CURLE_SSL_PEER_CERTIFICATE: - return "SSL peer certificate was not ok"; - - case CURLE_GOT_NOTHING: - return "server returned nothing (no headers, no data)"; - - case CURLE_SSL_ENGINE_NOTFOUND: - return "SSL crypto engine not found"; - - case CURLE_SSL_ENGINE_SETFAILED: - return "can not set SSL crypto engine as default"; - - case CURLE_SSL_ENGINE_INITFAILED: - return "failed to initialise SSL crypto engine"; - - case CURLE_SEND_ERROR: - return "failed sending data to the peer"; - - case CURLE_RECV_ERROR: - return "failure when receiving data from the peer"; - - case CURLE_SHARE_IN_USE: - return "share is already in use"; - - case CURLE_SSL_CERTPROBLEM: - return "problem with the local SSL certificate"; - - case CURLE_SSL_CIPHER: - return "couldn't use specified SSL cipher"; - - case CURLE_SSL_CACERT: - return "peer certificate cannot be authenticated with known CA certificates"; - - case CURLE_SSL_CACERT_BADFILE: - return "problem with the SSL CA cert (path? access rights?)"; - - case CURLE_BAD_CONTENT_ENCODING: - return "Unrecognized HTTP Content-Encoding"; - - case CURLE_LDAP_INVALID_URL: - return "Invalid LDAP URL"; - - case CURLE_FILESIZE_EXCEEDED: - return "Maximum file size exceeded"; - - case CURLE_FTP_SSL_FAILED: - return "Requested FTP SSL level failed"; - - case CURLE_SSL_SHUTDOWN_FAILED: - return "Failed to shut down the SSL connection"; - - case CURLE_SEND_FAIL_REWIND: - return "Send failed since rewinding of the data stream failed"; - - case CURLE_LOGIN_DENIED: - return "FTP: login denied"; - - case CURLE_TFTP_NOTFOUND: - return "TFTP: File Not Found"; - - case CURLE_TFTP_PERM: - return "TFTP: Access Violation"; - - case CURLE_TFTP_DISKFULL: - return "TFTP: Disk full or allocation exceeded"; - - case CURLE_TFTP_ILLEGAL: - return "TFTP: Illegal operation"; - - case CURLE_TFTP_UNKNOWNID: - return "TFTP: Unknown transfer ID"; - - case CURLE_TFTP_EXISTS: - return "TFTP: File already exists"; - - case CURLE_TFTP_NOSUCHUSER: - return "TFTP: No such user"; - - case CURLE_CONV_FAILED: - return "conversion failed"; - - case CURLE_CONV_REQD: - return "caller must register CURLOPT_CONV_ callback options"; - - case CURLE_REMOTE_FILE_NOT_FOUND: - return "Remote file not found"; - - case CURLE_SSH: - return "Error in the SSH layer"; - - /* error codes not used by current libcurl */ - case CURLE_FTP_USER_PASSWORD_INCORRECT: - case CURLE_MALFORMAT_USER: - case CURLE_BAD_CALLING_ORDER: - case CURLE_BAD_PASSWORD_ENTERED: - case CURLE_OBSOLETE: - case CURL_LAST: - break; - } - /* - * 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 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. 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. - */ - return "unknown error"; -#else - if (error == CURLE_OK) - return "no error"; - else - return "error"; -#endif -} - -const char * -curl_multi_strerror(CURLMcode error) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (error) { - case CURLM_CALL_MULTI_PERFORM: - return "please call curl_multi_perform() soon"; - - case CURLM_OK: - return "no error"; - - case CURLM_BAD_HANDLE: - return "invalid multi handle"; - - case CURLM_BAD_EASY_HANDLE: - return "invalid easy handle"; - - case CURLM_OUT_OF_MEMORY: - return "out of memory"; - - case CURLM_INTERNAL_ERROR: - return "internal error"; - - case CURLM_BAD_SOCKET: - return "invalid socket argument"; - - case CURLM_UNKNOWN_OPTION: - return "unknown option"; - - case CURLM_LAST: - break; - } - - return "unknown error"; -#else - if (error == CURLM_OK) - return "no error"; - else - return "error"; -#endif -} - -const char * -curl_share_strerror(CURLSHcode error) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (error) { - case CURLSHE_OK: - return "no error"; - - case CURLSHE_BAD_OPTION: - return "unknown share option"; - - case CURLSHE_IN_USE: - return "share currently in use"; - - case CURLSHE_INVALID: - return "invalid share handle"; - - case CURLSHE_NOMEM: - return "out of memory"; - - case CURLSHE_LAST: - break; - } - - return "CURLSH unknown"; -#else - if (error == CURLSHE_OK) - return "no error"; - else - return "error"; -#endif -} - -#ifdef USE_WINSOCK - -/* This function handles most / all (?) Winsock errors cURL is able to produce. - */ -static const char * -get_winsock_error (int err, char *buf, size_t len) -{ - const char *p; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (err) { - case WSAEINTR: - p = "Call interrupted."; - break; - case WSAEBADF: - p = "Bad file"; - break; - case WSAEACCES: - p = "Bad access"; - break; - case WSAEFAULT: - p = "Bad argument"; - break; - case WSAEINVAL: - p = "Invalid arguments"; - break; - case WSAEMFILE: - p = "Out of file descriptors"; - break; - case WSAEWOULDBLOCK: - p = "Call would block"; - break; - case WSAEINPROGRESS: - case WSAEALREADY: - p = "Blocking call in progress"; - break; - case WSAENOTSOCK: - p = "Descriptor is not a socket."; - break; - case WSAEDESTADDRREQ: - p = "Need destination address"; - break; - case WSAEMSGSIZE: - p = "Bad message size"; - break; - case WSAEPROTOTYPE: - p = "Bad protocol"; - break; - case WSAENOPROTOOPT: - p = "Protocol option is unsupported"; - break; - case WSAEPROTONOSUPPORT: - p = "Protocol is unsupported"; - break; - case WSAESOCKTNOSUPPORT: - p = "Socket is unsupported"; - break; - case WSAEOPNOTSUPP: - p = "Operation not supported"; - break; - case WSAEAFNOSUPPORT: - p = "Address family not supported"; - break; - case WSAEPFNOSUPPORT: - p = "Protocol family not supported"; - break; - case WSAEADDRINUSE: - p = "Address already in use"; - break; - case WSAEADDRNOTAVAIL: - p = "Address not available"; - break; - case WSAENETDOWN: - p = "Network down"; - break; - case WSAENETUNREACH: - p = "Network unreachable"; - break; - case WSAENETRESET: - p = "Network has been reset"; - break; - case WSAECONNABORTED: - p = "Connection was aborted"; - break; - case WSAECONNRESET: - p = "Connection was reset"; - break; - case WSAENOBUFS: - p = "No buffer space"; - break; - case WSAEISCONN: - p = "Socket is already connected"; - break; - case WSAENOTCONN: - p = "Socket is not connected"; - break; - case WSAESHUTDOWN: - p = "Socket has been shut down"; - break; - case WSAETOOMANYREFS: - p = "Too many references"; - break; - case WSAETIMEDOUT: - p = "Timed out"; - break; - case WSAECONNREFUSED: - p = "Connection refused"; - break; - case WSAELOOP: - p = "Loop??"; - break; - case WSAENAMETOOLONG: - p = "Name too long"; - break; - case WSAEHOSTDOWN: - p = "Host down"; - break; - case WSAEHOSTUNREACH: - p = "Host unreachable"; - break; - case WSAENOTEMPTY: - p = "Not empty"; - break; - case WSAEPROCLIM: - p = "Process limit reached"; - break; - case WSAEUSERS: - p = "Too many users"; - break; - case WSAEDQUOT: - p = "Bad quota"; - break; - case WSAESTALE: - p = "Something is stale"; - break; - case WSAEREMOTE: - p = "Remote error"; - break; -#ifdef WSAEDISCON /* missing in SalfordC! */ - case WSAEDISCON: - p = "Disconnected"; - break; -#endif - /* Extended Winsock errors */ - case WSASYSNOTREADY: - p = "Winsock library is not ready"; - break; - case WSANOTINITIALISED: - p = "Winsock library not initialised"; - break; - case WSAVERNOTSUPPORTED: - p = "Winsock version not supported."; - break; - - /* getXbyY() errors (already handled in herrmsg): - * Authoritative Answer: Host not found */ - case WSAHOST_NOT_FOUND: - p = "Host not found"; - break; - - /* Non-Authoritative: Host not found, or SERVERFAIL */ - case WSATRY_AGAIN: - p = "Host not found, try again"; - break; - - /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ - case WSANO_RECOVERY: - p = "Unrecoverable error in call to nameserver"; - break; - - /* Valid name, no data record of requested type */ - case WSANO_DATA: - p = "No data record of requested type"; - break; - - default: - return NULL; - } -#else - if (error == CURLE_OK) - return NULL; - else - p = "error"; -#endif - strncpy (buf, p, len); - buf [len-1] = '\0'; - return buf; -} -#endif /* USE_WINSOCK */ - -/* - * Our thread-safe and smart strerror() replacement. - * - * 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" convertion function and there might - * be systems that don't do proper range checking in there themselves. - * - * We don't do range checking (on systems other than Windows) since there is - * no good reliable and portable way to do it. - */ -const char *Curl_strerror(struct connectdata *conn, int err) -{ - char *buf, *p; - size_t max; - - curlassert(conn); - curlassert(err >= 0); - - buf = conn->syserr_buf; - max = sizeof(conn->syserr_buf)-1; - *buf = '\0'; - -#ifdef USE_WINSOCK - -#ifdef _WIN32_WCE - buf[0]=0; - { - wchar_t wbuf[256]; - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, - LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL); - wcstombs(buf,wbuf,max); - } - -#else - - /* 'sys_nerr' is the maximum errno number, it is not widely portable */ - if (err >= 0 && err < sys_nerr) - strncpy(buf, strerror(err), max); - else { - if (!get_winsock_error(err, buf, max) && - !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, - LANG_NEUTRAL, buf, (DWORD)max, NULL)) - snprintf(buf, max, "Unknown error %d (%#x)", err, err); - } -#endif -#else /* not USE_WINSOCK coming up */ - - /* These should be atomic and hopefully thread-safe */ -#ifdef HAVE_STRERROR_R - /* There are two different APIs for strerror_r(). The POSIX and the GLIBC - versions. */ -#ifdef HAVE_POSIX_STRERROR_R - strerror_r(err, buf, max); - /* this may set errno to ERANGE if insufficient storage was supplied via - 'strerrbuf' and 'buflen' to contain the generated message string, or - EINVAL if the value of 'errnum' is not a valid error number.*/ -#else - { - /* HAVE_GLIBC_STRERROR_R */ - char buffer[256]; - char *msg = strerror_r(err, buffer, sizeof(buffer)); - /* this version of strerror_r() only *might* use the buffer we pass to - the function, but it always returns the error message as a pointer, - so we must copy that string unconditionally (if non-NULL) */ - if(msg) - strncpy(buf, msg, max); - else - snprintf(buf, max, "Unknown error %d", err); - } -#endif /* end of HAVE_GLIBC_STRERROR_R */ -#else /* HAVE_STRERROR_R */ - strncpy(buf, strerror(err), max); -#endif /* end of HAVE_STRERROR_R */ -#endif /* end of ! USE_WINSOCK */ - - buf[max] = '\0'; /* make sure the string is zero terminated */ - - /* strip trailing '\r\n' or '\n'. */ - if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2) - *p = '\0'; - if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1) - *p = '\0'; - return buf; -} - -#ifdef USE_LIBIDN -/* - * Return error-string for libidn status as returned from idna_to_ascii_lz(). - */ -const char *Curl_idn_strerror (struct connectdata *conn, int err) -{ -#ifdef HAVE_IDNA_STRERROR - (void)conn; - return idna_strerror((Idna_rc) err); -#else - const char *str; - char *buf; - size_t max; - - curlassert(conn); - - buf = conn->syserr_buf; - max = sizeof(conn->syserr_buf)-1; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch ((Idna_rc)err) { - case IDNA_SUCCESS: - str = "No error"; - break; - case IDNA_STRINGPREP_ERROR: - str = "Error in string preparation"; - break; - case IDNA_PUNYCODE_ERROR: - str = "Error in Punycode operation"; - break; - case IDNA_CONTAINS_NON_LDH: - str = "Illegal ASCII characters"; - break; - case IDNA_CONTAINS_MINUS: - str = "Contains minus"; - break; - case IDNA_INVALID_LENGTH: - str = "Invalid output length"; - break; - case IDNA_NO_ACE_PREFIX: - str = "No ACE prefix (\"xn--\")"; - break; - case IDNA_ROUNDTRIP_VERIFY_ERROR: - str = "Roundtrip verify error"; - break; - case IDNA_CONTAINS_ACE_PREFIX: - str = "Already have ACE prefix (\"xn--\")"; - break; - case IDNA_ICONV_ERROR: - str = "Locale conversion failed"; - break; - case IDNA_MALLOC_ERROR: - str = "Allocation failed"; - break; - case IDNA_DLOPEN_ERROR: - str = "dlopen() error"; - break; - default: - snprintf(buf, max, "error %d", (int)err); - str = NULL; - break; - } -#else - if ((Idna_rc)err == IDNA_SUCCESS) - str = "No error"; - else - str = "error"; -#endif - if (str) - strncpy(buf, str, max); - buf[max] = '\0'; - return (buf); -#endif -} -#endif /* USE_LIBIDN */ diff --git a/Utilities/cmcurl/strerror.h b/Utilities/cmcurl/strerror.h deleted file mode 100644 index b280504..0000000 --- a/Utilities/cmcurl/strerror.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __CURL_STRERROR_H -#define __CURL_STRERROR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "urldata.h" - -const char *Curl_strerror (struct connectdata *conn, int err); - -#ifdef USE_LIBIDN -const char *Curl_idn_strerror (struct connectdata *conn, int err); -#endif - -#endif diff --git a/Utilities/cmcurl/strtok.c b/Utilities/cmcurl/strtok.c deleted file mode 100644 index 630e4e0..0000000 --- a/Utilities/cmcurl/strtok.c +++ /dev/null @@ -1,68 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef HAVE_STRTOK_R -#include -#include - -#include "strtok.h" - -char * -Curl_strtok_r(char *ptr, const char *sep, char **end) -{ - if (!ptr) - /* we got NULL input so then we get our last position instead */ - ptr = *end; - - /* pass all letters that are including in the separator string */ - while (*ptr && strchr(sep, *ptr)) - ++ptr; - - if (*ptr) { - /* so this is where the next piece of string starts */ - char *start = ptr; - - /* set the end pointer to the first byte after the start */ - *end = start + 1; - - /* scan through the string to find where it ends, it ends on a - null byte or a character that exists in the separator string */ - while (**end && !strchr(sep, **end)) - ++*end; - - if (**end) { - /* the end is not a null byte */ - **end = '\0'; /* zero terminate it! */ - ++*end; /* advance the last pointer to beyond the null byte */ - } - - return start; /* return the position where the string starts */ - } - - /* we ended up on a null byte, there are no more strings to find! */ - return NULL; -} - -#endif /* this was only compiled if strtok_r wasn't present */ diff --git a/Utilities/cmcurl/strtok.h b/Utilities/cmcurl/strtok.h deleted file mode 100644 index cf9fac8..0000000 --- a/Utilities/cmcurl/strtok.h +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#ifndef _CURL_STRTOK_R_H -#define _CURL_STRTOK_R_H - -#include "setup.h" -#include - -#ifndef HAVE_STRTOK_R -char *Curl_strtok_r(char *s, const char *delim, char **last); -#define strtok_r Curl_strtok_r -#else -#include -#endif - -#endif - diff --git a/Utilities/cmcurl/strtoofft.c b/Utilities/cmcurl/strtoofft.c deleted file mode 100644 index 3ab1bfd..0000000 --- a/Utilities/cmcurl/strtoofft.c +++ /dev/null @@ -1,165 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" -#include "strtoofft.h" - -/* - * NOTE: - * - * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we - * could use in case strtoll() doesn't exist... See - * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html - */ - -#ifdef NEED_CURL_STRTOLL -#include -#include -#include - -static int get_char(char c, int base); - -/** - * Emulated version of the strtoll function. This extracts a long long - * value from the given input string and returns it. - */ -curl_off_t -curlx_strtoll(const char *nptr, char **endptr, int base) -{ - char *end; - int is_negative = 0; - int overflow; - int i; - curl_off_t value = 0; - curl_off_t newval; - - /* Skip leading whitespace. */ - end = (char *)nptr; - while (ISSPACE(end[0])) { - end++; - } - - /* Handle the sign, if any. */ - if (end[0] == '-') { - is_negative = 1; - end++; - } - else if (end[0] == '+') { - end++; - } - else if (end[0] == '\0') { - /* We had nothing but perhaps some whitespace -- there was no number. */ - if (endptr) { - *endptr = end; - } - return 0; - } - - /* Handle special beginnings, if present and allowed. */ - if (end[0] == '0' && end[1] == 'x') { - if (base == 16 || base == 0) { - end += 2; - base = 16; - } - } - else if (end[0] == '0') { - if (base == 8 || base == 0) { - end++; - base = 8; - } - } - - /* 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)) { - newval = base * value + i; - if (newval < value) { - /* We've overflowed. */ - overflow = 1; - break; - } - else - value = newval; - } - - if (!overflow) { - if (is_negative) { - /* Fix the sign. */ - value *= -1; - } - } - else { - if (is_negative) - value = CURL_LLONG_MIN; - else - value = CURL_LLONG_MAX; - - errno = ERANGE; - } - - if (endptr) - *endptr = end; - - return value; -} - -/** - * Returns the value of c in the given base, or -1 if c cannot - * be interpreted properly in that base (i.e., is out of range, - * is a null, etc.). - * - * @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 isn't in range - */ -static int get_char(char c, int base) -{ - int value = -1; - if (c <= '9' && c >= '0') { - value = c - '0'; - } - else if (c <= 'Z' && c >= 'A') { - value = c - 'A' + 10; - } - else if (c <= 'z' && c >= 'a') { - value = c - 'a' + 10; - } - - if (value >= base) { - value = -1; - } - - return value; -} -#endif /* Only present if we need strtoll, but don't have it. */ diff --git a/Utilities/cmcurl/strtoofft.h b/Utilities/cmcurl/strtoofft.h deleted file mode 100644 index e27b432..0000000 --- a/Utilities/cmcurl/strtoofft.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _CURL_STRTOOFFT_H -#define _CURL_STRTOOFFT_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2004, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * CAUTION: this header is designed to work when included by the app-side - * as well as the library. Do not mix with library internals! - */ - -#include "setup.h" -#include -#include /* for the curl_off_t type */ - -/* Determine what type of file offset conversion handling we wish to use. For - * systems with a 32-bit curl_off_t type, we should use strtol. For systems - * with a 64-bit curl_off_t type, we should use strtoll if it exists, and if - * not, should try to emulate its functionality. At any rate, we define - * 'strtoofft' such that it can be used to work with curl_off_t's regardless. - */ -#if (SIZEOF_CURL_OFF_T > 4) && (SIZEOF_LONG < 8) -#if HAVE_STRTOLL -#define curlx_strtoofft strtoll -#else /* HAVE_STRTOLL */ - -/* For MSVC7 we can use _strtoi64() which seems to be a strtoll() clone */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) -#define curlx_strtoofft _strtoi64 -#else /* MSVC7 or later */ -curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base); -#define curlx_strtoofft curlx_strtoll -#define NEED_CURL_STRTOLL -#endif /* MSVC7 or later */ - -#endif /* HAVE_STRTOLL */ -#else /* (SIZEOF_CURL_OFF_T > 4) && (SIZEOF_LONG < 8) */ -/* simply use strtol() to get numbers, either 32 or 64 bit */ -#define curlx_strtoofft strtol -#endif - -#if defined(_MSC_VER) || defined(__WATCOMC__) -#define CURL_LLONG_MIN 0x8000000000000000i64 -#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFi64 -#elif defined(HAVE_LL) -#define CURL_LLONG_MIN 0x8000000000000000LL -#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFLL -#else -#define CURL_LLONG_MIN 0x8000000000000000L -#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFL -#endif - -#endif - diff --git a/Utilities/cmcurl/telnet.c b/Utilities/cmcurl/telnet.c deleted file mode 100644 index 97d22b7..0000000 --- a/Utilities/cmcurl/telnet.c +++ /dev/null @@ -1,1403 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_TELNET -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#if defined(WIN32) -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - - -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "telnet.h" -#include "connect.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#define TELOPTS -#define TELCMDS - -#include "arpa_telnet.h" -#include "memory.h" -#include "select.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#define SUBBUFSIZE 512 - -#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer; -#define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); } -#define CURL_SB_ACCUM(x,c) \ - if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \ - *x->subpointer++ = (c); \ - } - -#define CURL_SB_GET(x) ((*x->subpointer++)&0xff) -#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) -#define CURL_SB_EOF(x) (x->subpointer >= x->subend) -#define CURL_SB_LEN(x) (x->subend - x->subpointer) - -#ifdef USE_WINSOCK -typedef FARPROC WSOCK2_FUNC; -static CURLcode check_wsock2 ( struct SessionHandle *data ); -#endif - -static -void telrcv(struct connectdata *, - unsigned char *inbuf, /* Data received from socket */ - ssize_t count); /* Number of bytes received */ - -static void printoption(struct SessionHandle *data, - const char *direction, - int cmd, int option); - -static void negotiate(struct connectdata *); -static void send_negotiation(struct connectdata *, int cmd, int option); -static void set_local_option(struct connectdata *, int cmd, int option); -static void set_remote_option(struct connectdata *, int cmd, int option); - -static void printsub(struct SessionHandle *data, - int direction, unsigned char *pointer, - size_t length); -static void suboption(struct connectdata *); - -/* For negotiation compliant to RFC 1143 */ -#define CURL_NO 0 -#define CURL_YES 1 -#define CURL_WANTYES 2 -#define CURL_WANTNO 3 - -#define CURL_EMPTY 0 -#define CURL_OPPOSITE 1 - -/* - * Telnet receiver states for fsm - */ -typedef enum -{ - CURL_TS_DATA = 0, - CURL_TS_IAC, - CURL_TS_WILL, - CURL_TS_WONT, - CURL_TS_DO, - CURL_TS_DONT, - CURL_TS_CR, - CURL_TS_SB, /* sub-option collection */ - CURL_TS_SE /* looking for sub-option end */ -} TelnetReceive; - -struct TELNET { - int please_negotiate; - int already_negotiated; - int us[256]; - int usq[256]; - int us_preferred[256]; - int him[256]; - int himq[256]; - int him_preferred[256]; - char subopt_ttype[32]; /* Set with suboption TTYPE */ - char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ - struct curl_slist *telnet_vars; /* Environment variables */ - - /* suboptions */ - unsigned char subbuffer[SUBBUFSIZE]; - unsigned char *subpointer, *subend; /* buffer for sub-options */ - - TelnetReceive telrcv_state; -}; - -#ifdef USE_WINSOCK -static CURLcode -check_wsock2 ( struct SessionHandle *data ) -{ - int err; - WORD wVersionRequested; - WSADATA wsaData; - - curlassert(data); - - /* telnet requires at least WinSock 2.0 so ask for it. */ - wVersionRequested = MAKEWORD(2, 0); - - err = WSAStartup(wVersionRequested, &wsaData); - - /* We must've called this once already, so this call */ - /* should always succeed. But, just in case... */ - if (err != 0) { - failf(data,"WSAStartup failed (%d)",err); - return CURLE_FAILED_INIT; - } - - /* We have to have a WSACleanup call for every successful */ - /* WSAStartup call. */ - WSACleanup(); - - /* Check that our version is supported */ - if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || - HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) { - /* Our version isn't supported */ - failf(data,"insufficient winsock version to support " - "telnet"); - return CURLE_FAILED_INIT; - } - - /* Our version is supported */ - return CURLE_OK; -} -#endif - -static -CURLcode init_telnet(struct connectdata *conn) -{ - struct TELNET *tn; - - tn = (struct TELNET *)calloc(1, sizeof(struct TELNET)); - if(!tn) - return CURLE_OUT_OF_MEMORY; - - conn->data->reqdata.proto.telnet = (void *)tn; /* make us known */ - - tn->telrcv_state = CURL_TS_DATA; - - /* Init suboptions */ - CURL_SB_CLEAR(tn); - - /* Set the options we want by default */ - tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; - tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; - tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; - tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; - - return CURLE_OK; -} - -static void negotiate(struct connectdata *conn) -{ - int i; - struct TELNET *tn = (struct TELNET *) conn->data->reqdata.proto.telnet; - - for(i = 0;i < CURL_NTELOPTS;i++) - { - if(tn->us_preferred[i] == CURL_YES) - set_local_option(conn, i, CURL_YES); - - if(tn->him_preferred[i] == CURL_YES) - set_remote_option(conn, i, CURL_YES); - } -} - -static void printoption(struct SessionHandle *data, - const char *direction, int cmd, int option) -{ - const char *fmt; - const char *opt; - - if (data->set.verbose) - { - if (cmd == CURL_IAC) - { - if (CURL_TELCMD_OK(option)) - infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option)); - else - infof(data, "%s IAC %d\n", direction, option); - } - else - { - fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" : - (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0; - if (fmt) - { - if (CURL_TELOPT_OK(option)) - opt = CURL_TELOPT(option); - else if (option == CURL_TELOPT_EXOPL) - opt = "EXOPL"; - else - opt = NULL; - - if(opt) - infof(data, "%s %s %s\n", direction, fmt, opt); - else - infof(data, "%s %s %d\n", direction, fmt, option); - } - else - infof(data, "%s %d %d\n", direction, cmd, option); - } - } -} - -static void send_negotiation(struct connectdata *conn, int cmd, int option) -{ - unsigned char buf[3]; - ssize_t bytes_written; - int err; - struct SessionHandle *data = conn->data; - - buf[0] = CURL_IAC; - buf[1] = (unsigned char)cmd; - buf[2] = (unsigned char)option; - - bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); - if(bytes_written < 0) { - err = Curl_sockerrno(); - failf(data,"Sending data failed (%d)",err); - } - - printoption(conn->data, "SENT", cmd, option); -} - -static -void set_remote_option(struct connectdata *conn, int option, int newstate) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - if(newstate == CURL_YES) - { - switch(tn->him[option]) - { - case CURL_NO: - tn->him[option] = CURL_WANTYES; - send_negotiation(conn, CURL_DO, option); - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Already negotiating for CURL_YES, queue the request */ - tn->himq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Error: already negotiating for enable */ - break; - case CURL_OPPOSITE: - tn->himq[option] = CURL_EMPTY; - break; - } - break; - } - } - else /* NO */ - { - switch(tn->him[option]) - { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->him[option] = CURL_WANTNO; - send_negotiation(conn, CURL_DONT, option); - break; - - case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Already negotiating for NO */ - break; - case CURL_OPPOSITE: - tn->himq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->himq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - break; - } - break; - } - } -} - -static -void rec_will(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - switch(tn->him[option]) - { - case CURL_NO: - if(tn->him_preferred[option] == CURL_YES) - { - tn->him[option] = CURL_YES; - send_negotiation(conn, CURL_DO, option); - } - else - { - send_negotiation(conn, CURL_DONT, option); - } - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Error: DONT answered by WILL */ - tn->him[option] = CURL_NO; - break; - case CURL_OPPOSITE: - /* Error: DONT answered by WILL */ - tn->him[option] = CURL_YES; - tn->himq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->him[option] = CURL_YES; - break; - case CURL_OPPOSITE: - tn->him[option] = CURL_WANTNO; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_DONT, option); - break; - } - break; - } -} - -static -void rec_wont(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - switch(tn->him[option]) - { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->him[option] = CURL_NO; - send_negotiation(conn, CURL_DONT, option); - break; - - case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->him[option] = CURL_NO; - break; - - case CURL_OPPOSITE: - tn->him[option] = CURL_WANTYES; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_DO, option); - break; - } - break; - - case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->him[option] = CURL_NO; - break; - case CURL_OPPOSITE: - tn->him[option] = CURL_NO; - tn->himq[option] = CURL_EMPTY; - break; - } - break; - } -} - -static void -set_local_option(struct connectdata *conn, int option, int newstate) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - if(newstate == CURL_YES) - { - switch(tn->us[option]) - { - case CURL_NO: - tn->us[option] = CURL_WANTYES; - send_negotiation(conn, CURL_WILL, option); - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Already negotiating for CURL_YES, queue the request */ - tn->usq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Error: already negotiating for enable */ - break; - case CURL_OPPOSITE: - tn->usq[option] = CURL_EMPTY; - break; - } - break; - } - } - else /* NO */ - { - switch(tn->us[option]) - { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->us[option] = CURL_WANTNO; - send_negotiation(conn, CURL_WONT, option); - break; - - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Already negotiating for NO */ - break; - case CURL_OPPOSITE: - tn->usq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->usq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - break; - } - break; - } - } -} - -static -void rec_do(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - switch(tn->us[option]) - { - case CURL_NO: - if(tn->us_preferred[option] == CURL_YES) - { - tn->us[option] = CURL_YES; - send_negotiation(conn, CURL_WILL, option); - } - else - { - send_negotiation(conn, CURL_WONT, option); - } - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Error: DONT answered by WILL */ - tn->us[option] = CURL_NO; - break; - case CURL_OPPOSITE: - /* Error: DONT answered by WILL */ - tn->us[option] = CURL_YES; - tn->usq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->us[option] = CURL_YES; - break; - case CURL_OPPOSITE: - tn->us[option] = CURL_WANTNO; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_WONT, option); - break; - } - break; - } -} - -static -void rec_dont(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - switch(tn->us[option]) - { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->us[option] = CURL_NO; - send_negotiation(conn, CURL_WONT, option); - break; - - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->us[option] = CURL_NO; - break; - - case CURL_OPPOSITE: - tn->us[option] = CURL_WANTYES; - tn->usq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_WILL, option); - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->us[option] = CURL_NO; - break; - case CURL_OPPOSITE: - tn->us[option] = CURL_NO; - tn->usq[option] = CURL_EMPTY; - break; - } - break; - } -} - - -static void printsub(struct SessionHandle *data, - int direction, /* '<' or '>' */ - unsigned char *pointer, /* where suboption data is */ - size_t length) /* length of suboption data */ -{ - unsigned int i = 0; - - if (data->set.verbose) - { - if (direction) - { - infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); - if (length >= 3) - { - int j; - - i = pointer[length-2]; - j = pointer[length-1]; - - if (i != CURL_IAC || j != CURL_SE) - { - infof(data, "(terminated by "); - if (CURL_TELOPT_OK(i)) - infof(data, "%s ", CURL_TELOPT(i)); - else if (CURL_TELCMD_OK(i)) - infof(data, "%s ", CURL_TELCMD(i)); - else - infof(data, "%d ", i); - if (CURL_TELOPT_OK(j)) - infof(data, "%s", CURL_TELOPT(j)); - else if (CURL_TELCMD_OK(j)) - infof(data, "%s", CURL_TELCMD(j)); - else - infof(data, "%d", j); - infof(data, ", not IAC SE!) "); - } - } - length -= 2; - } - if (length < 1) - { - infof(data, "(Empty suboption?)"); - return; - } - - if (CURL_TELOPT_OK(pointer[0])) { - switch(pointer[0]) { - case CURL_TELOPT_TTYPE: - case CURL_TELOPT_XDISPLOC: - case CURL_TELOPT_NEW_ENVIRON: - infof(data, "%s", CURL_TELOPT(pointer[0])); - break; - default: - infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); - break; - } - } - else - infof(data, "%d (unknown)", pointer[i]); - - switch(pointer[1]) { - case CURL_TELQUAL_IS: - infof(data, " IS"); - break; - case CURL_TELQUAL_SEND: - infof(data, " SEND"); - break; - case CURL_TELQUAL_INFO: - infof(data, " INFO/REPLY"); - break; - case CURL_TELQUAL_NAME: - infof(data, " NAME"); - break; - } - - switch(pointer[0]) { - case CURL_TELOPT_TTYPE: - case CURL_TELOPT_XDISPLOC: - pointer[length] = 0; - infof(data, " \"%s\"", &pointer[2]); - break; - case CURL_TELOPT_NEW_ENVIRON: - if(pointer[1] == CURL_TELQUAL_IS) { - infof(data, " "); - for(i = 3;i < length;i++) { - switch(pointer[i]) { - case CURL_NEW_ENV_VAR: - infof(data, ", "); - break; - case CURL_NEW_ENV_VALUE: - infof(data, " = "); - break; - default: - infof(data, "%c", pointer[i]); - break; - } - } - } - break; - default: - for (i = 2; i < length; i++) - infof(data, " %.2x", pointer[i]); - break; - } - - if (direction) - { - infof(data, "\n"); - } - } -} - -static CURLcode check_telnet_options(struct connectdata *conn) -{ - struct curl_slist *head; - char option_keyword[128]; - char option_arg[256]; - char *buf; - struct SessionHandle *data = conn->data; - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - - /* Add the user name as an environment variable if it - was given on the command line */ - if(conn->bits.user_passwd) - { - snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg); - - tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; - } - - for(head = data->set.telnet_options; head; head=head->next) { - if(sscanf(head->data, "%127[^= ]%*[ =]%255s", - option_keyword, option_arg) == 2) { - - /* Terminal type */ - if(curl_strequal(option_keyword, "TTYPE")) { - strncpy(tn->subopt_ttype, option_arg, 31); - tn->subopt_ttype[31] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; - continue; - } - - /* Display variable */ - if(curl_strequal(option_keyword, "XDISPLOC")) { - strncpy(tn->subopt_xdisploc, option_arg, 127); - tn->subopt_xdisploc[127] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; - continue; - } - - /* Environment variable */ - if(curl_strequal(option_keyword, "NEW_ENV")) { - buf = strdup(option_arg); - if(!buf) - return CURLE_OUT_OF_MEMORY; - tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf); - tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; - continue; - } - - failf(data, "Unknown telnet option %s", head->data); - return CURLE_UNKNOWN_TELNET_OPTION; - } else { - failf(data, "Syntax error in telnet option: %s", head->data); - return CURLE_TELNET_OPTION_SYNTAX; - } - } - - return CURLE_OK; -} - -/* - * suboption() - * - * Look at the sub-option buffer, and try to be helpful to the other - * side. - */ - -static void suboption(struct connectdata *conn) -{ - struct curl_slist *v; - unsigned char temp[2048]; - ssize_t bytes_written; - size_t len; - size_t tmplen; - int err; - char varname[128]; - char varval[128]; - struct SessionHandle *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; - - printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2); - switch (CURL_SB_GET(tn)) { - case CURL_TELOPT_TTYPE: - len = strlen(tn->subopt_ttype) + 4 + 2; - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, - CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); - bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); - if(bytes_written < 0) { - err = Curl_sockerrno(); - failf(data,"Sending data failed (%d)",err); - } - printsub(data, '>', &temp[2], len-2); - break; - case CURL_TELOPT_XDISPLOC: - len = strlen(tn->subopt_xdisploc) + 4 + 2; - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, - CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); - bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); - if(bytes_written < 0) { - err = Curl_sockerrno(); - failf(data,"Sending data failed (%d)",err); - } - printsub(data, '>', &temp[2], len-2); - break; - case CURL_TELOPT_NEW_ENVIRON: - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, - CURL_TELQUAL_IS); - len = 4; - - for(v = tn->telnet_vars;v;v = v->next) { - tmplen = (strlen(v->data) + 1); - /* Add the variable only if it fits */ - if(len + tmplen < (int)sizeof(temp)-6) { - sscanf(v->data, "%127[^,],%127s", varname, varval); - snprintf((char *)&temp[len], sizeof(temp) - len, - "%c%s%c%s", CURL_NEW_ENV_VAR, varname, - CURL_NEW_ENV_VALUE, varval); - len += tmplen; - } - } - snprintf((char *)&temp[len], sizeof(temp) - len, - "%c%c", CURL_IAC, CURL_SE); - len += 2; - bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); - if(bytes_written < 0) { - err = Curl_sockerrno(); - failf(data,"Sending data failed (%d)",err); - } - printsub(data, '>', &temp[2], len-2); - break; - } - return; -} - -static -void telrcv(struct connectdata *conn, - unsigned char *inbuf, /* Data received from socket */ - ssize_t count) /* Number of bytes received */ -{ - unsigned char c; - int in = 0; - struct SessionHandle *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; - - while(count--) - { - c = inbuf[in++]; - - switch (tn->telrcv_state) - { - case CURL_TS_CR: - tn->telrcv_state = CURL_TS_DATA; - if (c == '\0') - { - break; /* Ignore \0 after CR */ - } - - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); - continue; - - case CURL_TS_DATA: - if (c == CURL_IAC) - { - tn->telrcv_state = CURL_TS_IAC; - break; - } - else if(c == '\r') - { - tn->telrcv_state = CURL_TS_CR; - } - - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); - continue; - - case CURL_TS_IAC: - process_iac: - switch (c) - { - case CURL_WILL: - tn->telrcv_state = CURL_TS_WILL; - continue; - case CURL_WONT: - tn->telrcv_state = CURL_TS_WONT; - continue; - case CURL_DO: - tn->telrcv_state = CURL_TS_DO; - continue; - case CURL_DONT: - tn->telrcv_state = CURL_TS_DONT; - continue; - case CURL_SB: - CURL_SB_CLEAR(tn); - tn->telrcv_state = CURL_TS_SB; - continue; - case CURL_IAC: - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); - break; - case CURL_DM: - case CURL_NOP: - case CURL_GA: - default: - printoption(data, "RCVD", CURL_IAC, c); - break; - } - tn->telrcv_state = CURL_TS_DATA; - continue; - - case CURL_TS_WILL: - printoption(data, "RCVD", CURL_WILL, c); - tn->please_negotiate = 1; - rec_will(conn, c); - tn->telrcv_state = CURL_TS_DATA; - continue; - - case CURL_TS_WONT: - printoption(data, "RCVD", CURL_WONT, c); - tn->please_negotiate = 1; - rec_wont(conn, c); - tn->telrcv_state = CURL_TS_DATA; - continue; - - case CURL_TS_DO: - printoption(data, "RCVD", CURL_DO, c); - tn->please_negotiate = 1; - rec_do(conn, c); - tn->telrcv_state = CURL_TS_DATA; - continue; - - case CURL_TS_DONT: - printoption(data, "RCVD", CURL_DONT, c); - tn->please_negotiate = 1; - rec_dont(conn, c); - tn->telrcv_state = CURL_TS_DATA; - continue; - - case CURL_TS_SB: - if (c == CURL_IAC) - { - tn->telrcv_state = CURL_TS_SE; - } - else - { - CURL_SB_ACCUM(tn,c); - } - continue; - - case CURL_TS_SE: - 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 happend. 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 - * not doubled, and really the IAC SE was left off, we could get - * into an infinate loop here. So, instead, we terminate the - * suboption, and process the partial suboption if we can. - */ - CURL_SB_ACCUM(tn, CURL_IAC); - CURL_SB_ACCUM(tn, c); - tn->subpointer -= 2; - CURL_SB_TERM(tn); - - printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); - suboption(conn); /* handle sub-option */ - tn->telrcv_state = CURL_TS_IAC; - goto process_iac; - } - CURL_SB_ACCUM(tn,c); - tn->telrcv_state = CURL_TS_SB; - } - else - { - CURL_SB_ACCUM(tn, CURL_IAC); - CURL_SB_ACCUM(tn, CURL_SE); - tn->subpointer -= 2; - CURL_SB_TERM(tn); - suboption(conn); /* handle sub-option */ - tn->telrcv_state = CURL_TS_DATA; - } - break; - } - } -} - -CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premature) -{ - struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet; - (void)status; /* unused */ - (void)premature; /* not used */ - - curl_slist_free_all(tn->telnet_vars); - - free(conn->data->reqdata.proto.telnet); - conn->data->reqdata.proto.telnet = NULL; - - return CURLE_OK; -} - -CURLcode Curl_telnet(struct connectdata *conn, bool *done) -{ - CURLcode code; - struct SessionHandle *data = conn->data; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; -#ifdef USE_WINSOCK - HMODULE wsock2; - WSOCK2_FUNC close_event_func; - WSOCK2_FUNC create_event_func; - WSOCK2_FUNC event_select_func; - WSOCK2_FUNC enum_netevents_func; - WSAEVENT event_handle; - WSANETWORKEVENTS events; - HANDLE stdin_handle; - HANDLE objs[2]; - DWORD obj_count; - DWORD wait_timeout; - DWORD waitret; - DWORD readfile_read; -#else - int interval_ms; - struct pollfd pfd[2]; -#endif - ssize_t nread; - bool keepon = TRUE; - char *buf = data->state.buffer; - struct TELNET *tn; - - *done = TRUE; /* uncontionally */ - - code = init_telnet(conn); - if(code) - return code; - - tn = (struct TELNET *)data->reqdata.proto.telnet; - - code = check_telnet_options(conn); - if(code) - return code; - -#ifdef USE_WINSOCK - /* - ** This functionality only works with WinSock >= 2.0. So, - ** make sure have it. - */ - code = check_wsock2(data); - if (code) - return code; - - /* OK, so we have WinSock 2.0. We need to dynamically */ - /* load ws2_32.dll and get the function pointers we need. */ - wsock2 = LoadLibrary("WS2_32.DLL"); - if (wsock2 == NULL) { - failf(data,"failed to load WS2_32.DLL (%d)",GetLastError()); - return CURLE_FAILED_INIT; - } - - /* Grab a pointer to WSACreateEvent */ - create_event_func = GetProcAddress(wsock2,"WSACreateEvent"); - if (create_event_func == NULL) { - failf(data,"failed to find WSACreateEvent function (%d)", - GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* And WSACloseEvent */ - close_event_func = GetProcAddress(wsock2,"WSACloseEvent"); - if (close_event_func == NULL) { - failf(data,"failed to find WSACloseEvent function (%d)", - GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* And WSAEventSelect */ - event_select_func = GetProcAddress(wsock2,"WSAEventSelect"); - if (event_select_func == NULL) { - failf(data,"failed to find WSAEventSelect function (%d)", - GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* And WSAEnumNetworkEvents */ - enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents"); - if (enum_netevents_func == NULL) { - failf(data,"failed to find WSAEnumNetworkEvents function (%d)", - GetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* We want to wait for both stdin and the socket. Since - ** the select() function in winsock only works on sockets - ** we have to use the WaitForMultipleObjects() call. - */ - - /* First, create a sockets event object */ - event_handle = (WSAEVENT)create_event_func(); - if (event_handle == WSA_INVALID_EVENT) { - failf(data,"WSACreateEvent failed (%d)",WSAGetLastError()); - FreeLibrary(wsock2); - return CURLE_FAILED_INIT; - } - - /* The get the Windows file handle for stdin */ - stdin_handle = GetStdHandle(STD_INPUT_HANDLE); - - /* Create the list of objects to wait for */ - objs[0] = event_handle; - objs[1] = stdin_handle; - - /* Tell winsock what events we want to listen to */ - if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { - close_event_func(event_handle); - FreeLibrary(wsock2); - return 0; - } - - /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, - else use the old WaitForMultipleObjects() way */ - if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) { - /* Don't wait for stdin_handle, just wait for event_handle */ - obj_count = 1; - /* Check stdin_handle per 100 milliseconds */ - wait_timeout = 100; - } else { - obj_count = 2; - wait_timeout = INFINITE; - } - - /* Keep on listening and act on events */ - while(keepon) { - waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); - switch(waitret) { - case WAIT_TIMEOUT: - { - unsigned char outbuf[2]; - int out_count = 0; - ssize_t bytes_written; - char *buffer = buf; - - while(1) { - if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { - keepon = FALSE; - break; - } - nread = readfile_read; - - if(!nread) - break; - - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), - &readfile_read, NULL)) { - keepon = FALSE; - break; - } - nread = readfile_read; - - while(nread--) { - outbuf[0] = *buffer++; - out_count = 1; - if(outbuf[0] == CURL_IAC) - outbuf[out_count++] = CURL_IAC; - - Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, - out_count, &bytes_written); - } - } - } - break; - - case WAIT_OBJECT_0 + 1: - { - unsigned char outbuf[2]; - int out_count = 0; - ssize_t bytes_written; - char *buffer = buf; - - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), - &readfile_read, NULL)) { - keepon = FALSE; - break; - } - nread = readfile_read; - - while(nread--) { - outbuf[0] = *buffer++; - out_count = 1; - if(outbuf[0] == CURL_IAC) - outbuf[out_count++] = CURL_IAC; - - Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, - out_count, &bytes_written); - } - } - break; - - case WAIT_OBJECT_0: - if(enum_netevents_func(sockfd, event_handle, &events) - != SOCKET_ERROR) { - if(events.lNetworkEvents & FD_READ) { - /* This reallu OUGHT to check its return code. */ - (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); - - telrcv(conn, (unsigned char *)buf, nread); - - fflush(stdout); - - /* Negotiate if the peer has started negotiating, - 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(conn); - tn->already_negotiated = 1; - } - } - - if(events.lNetworkEvents & FD_CLOSE) { - keepon = FALSE; - } - } - break; - } - } - - /* We called WSACreateEvent, so call WSACloseEvent */ - if (close_event_func(event_handle) == FALSE) { - infof(data,"WSACloseEvent failed (%d)",WSAGetLastError()); - } - - /* "Forget" pointers into the library we're about to free */ - create_event_func = NULL; - close_event_func = NULL; - event_select_func = NULL; - enum_netevents_func = NULL; - - /* We called LoadLibrary, so call FreeLibrary */ - if (!FreeLibrary(wsock2)) - infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError()); -#else - pfd[0].fd = sockfd; - pfd[0].events = POLLIN; - pfd[1].fd = 0; - pfd[1].events = POLLIN; - interval_ms = 1 * 1000; - - while (keepon) { - switch (Curl_poll(pfd, 2, interval_ms)) { - case -1: /* error, stop reading */ - keepon = FALSE; - continue; - case 0: /* timeout */ - break; - default: /* read! */ - if(pfd[1].revents & POLLIN) { /* read from stdin */ - unsigned char outbuf[2]; - int out_count = 0; - ssize_t bytes_written; - char *buffer = buf; - - nread = read(0, buf, 255); - - while(nread--) { - outbuf[0] = *buffer++; - out_count = 1; - if(outbuf[0] == CURL_IAC) - outbuf[out_count++] = CURL_IAC; - - Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, - out_count, &bytes_written); - } - } - - if(pfd[0].revents & POLLIN) { - /* This OUGHT to check the return code... */ - (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); - - /* if we receive 0 or less here, the server closed the connection and - we bail out from this! */ - if (nread <= 0) { - keepon = FALSE; - break; - } - - telrcv(conn, (unsigned char *)buf, nread); - - /* Negotiate if the peer has started negotiating, - 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(conn); - tn->already_negotiated = 1; - } - } - } - if(data->set.timeout) { - struct timeval now; /* current time */ - now = Curl_tvnow(); - if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) { - failf(data, "Time-out"); - code = CURLE_OPERATION_TIMEOUTED; - keepon = FALSE; - } - } - } -#endif - /* mark this as "no further transfer wanted" */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - return code; -} -#endif diff --git a/Utilities/cmcurl/telnet.h b/Utilities/cmcurl/telnet.h deleted file mode 100644 index 693abf3..0000000 --- a/Utilities/cmcurl/telnet.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __TELNET_H -#define __TELNET_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_TELNET -CURLcode Curl_telnet(struct connectdata *conn, bool *done); -CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode, bool premature); -#endif -#endif diff --git a/Utilities/cmcurl/tftp.c b/Utilities/cmcurl/tftp.c deleted file mode 100644 index 0e2e7ab..0000000 --- a/Utilities/cmcurl/tftp.c +++ /dev/null @@ -1,816 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#ifndef CURL_DISABLE_TFTP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#if defined(WIN32) -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - - -#endif - -#include "urldata.h" -#include -#include "transfer.h" -#include "sendf.h" -#include "tftp.h" -#include "progress.h" -#include "connect.h" -#include "strerror.h" -#include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "memory.h" -#include "select.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* RFC2348 allows the block size to be negotiated, but we don't support that */ -#define TFTP_BLOCKSIZE 512 - -typedef enum { - TFTP_MODE_NETASCII=0, - TFTP_MODE_OCTET -} tftp_mode_t; - -typedef enum { - TFTP_STATE_START=0, - TFTP_STATE_RX, - TFTP_STATE_TX, - TFTP_STATE_FIN -} tftp_state_t; - -typedef enum { - TFTP_EVENT_INIT=0, - TFTP_EVENT_RRQ = 1, - TFTP_EVENT_WRQ = 2, - TFTP_EVENT_DATA = 3, - TFTP_EVENT_ACK = 4, - TFTP_EVENT_ERROR = 5, - TFTP_EVENT_TIMEOUT -} tftp_event_t; - -typedef enum { - TFTP_ERR_UNDEF=0, - TFTP_ERR_NOTFOUND, - TFTP_ERR_PERM, - TFTP_ERR_DISKFULL, - TFTP_ERR_ILLEGAL, - TFTP_ERR_UNKNOWNID, - TFTP_ERR_EXISTS, - TFTP_ERR_NOSUCHUSER, - TFTP_ERR_TIMEOUT, - TFTP_ERR_NORESPONSE -} tftp_error_t; - -typedef struct tftp_packet { - unsigned char data[2 + 2 + TFTP_BLOCKSIZE]; -} tftp_packet_t; - -typedef struct tftp_state_data { - tftp_state_t state; - tftp_mode_t mode; - tftp_error_t error; - struct connectdata *conn; - curl_socket_t sockfd; - int retries; - int retry_time; - int retry_max; - time_t start_time; - time_t max_time; - unsigned short block; - struct Curl_sockaddr_storage local_addr; - socklen_t local_addrlen; - struct Curl_sockaddr_storage remote_addr; - socklen_t remote_addrlen; - int rbytes; - int sbytes; - tftp_packet_t rpacket; - tftp_packet_t spacket; -} tftp_state_data_t; - - -/* Forward declarations */ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; -void tftp_set_timeouts(tftp_state_data_t *state) ; - -/********************************************************** - * - * tftp_set_timeouts - - * - * Set timeouts based on state machine state. - * Use user provided connect timeouts until DATA or ACK - * packet is received, then use user-provided transfer timeouts - * - * - **********************************************************/ -void tftp_set_timeouts(tftp_state_data_t *state) -{ - - struct SessionHandle *data = state->conn->data; - time_t maxtime, timeout; - - time(&state->start_time); - if(state->state == TFTP_STATE_START) { - /* Compute drop-dead time */ - maxtime = (time_t)(data->set.connecttimeout?data->set.connecttimeout:30); - state->max_time = state->start_time+maxtime; - - /* Set per-block timeout to total */ - timeout = maxtime ; - - /* Average restart after 5 seconds */ - state->retry_max = (int)(timeout/5); - - /* Compute the re-start interval to suit the timeout */ - state->retry_time = (int)(timeout/state->retry_max); - if(state->retry_time<1) - state->retry_time=1; - - } - else { - - /* Compute drop-dead time */ - maxtime = (time_t)(data->set.timeout?data->set.timeout:3600); - state->max_time = state->start_time+maxtime; - - /* Set per-block timeout to 10% of total */ - timeout = maxtime/10 ; - - /* Average reposting an ACK after 15 seconds */ - state->retry_max = (int)(timeout/15); - } - /* But bound the total number */ - if(state->retry_max<3) - state->retry_max=3; - - if(state->retry_max>50) - state->retry_max=50; - - /* Compute the re-ACK interval to suit the timeout */ - state->retry_time = (int)(timeout/state->retry_max); - if(state->retry_time<1) - state->retry_time=1; - - infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n", - state->state, (state->max_time-state->start_time), - state->retry_time, state->retry_max); -} - -/********************************************************** - * - * tftp_set_send_first - * - * Event handler for the START state - * - **********************************************************/ - -static void setpacketevent(tftp_packet_t *packet, unsigned short num) -{ - packet->data[0] = (unsigned char)(num >> 8); - packet->data[1] = (unsigned char)(num & 0xff); -} - - -static void setpacketblock(tftp_packet_t *packet, unsigned short num) -{ - packet->data[2] = (unsigned char)(num >> 8); - packet->data[3] = (unsigned char)(num & 0xff); -} - -static unsigned short getrpacketevent(tftp_packet_t *packet) -{ - return (unsigned short)((packet->data[0] << 8) | packet->data[1]); -} - -static unsigned short getrpacketblock(tftp_packet_t *packet) -{ - return (unsigned short)((packet->data[2] << 8) | packet->data[3]); -} - -static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) -{ - int sbytes; - const char *mode = "octet"; - char *filename; - struct SessionHandle *data = state->conn->data; - CURLcode res = CURLE_OK; - - /* Set ascii mode if -B flag was used */ - if(data->set.prefer_ascii) - mode = "netascii"; - - switch(event) { - - case TFTP_EVENT_INIT: /* Send the first packet out */ - case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */ - /* Increment the retry counter, quit if over the limit */ - state->retries++; - if(state->retries>state->retry_max) { - state->error = TFTP_ERR_NORESPONSE; - state->state = TFTP_STATE_FIN; - return res; - } - - if(data->set.upload) { - /* If we are uploading, send an WRQ */ - setpacketevent(&state->spacket, TFTP_EVENT_WRQ); - state->conn->data->reqdata.upload_fromhere = (char *)&state->spacket.data[4]; - if(data->set.infilesize != -1) - Curl_pgrsSetUploadSize(data, data->set.infilesize); - } - else { - /* If we are downloading, send an RRQ */ - setpacketevent(&state->spacket, TFTP_EVENT_RRQ); - } - /* As RFC3617 describes the separator slash is not actually part of the - file name so we skip the always-present first letter of the path string. */ - filename = curl_easy_unescape(data, &state->conn->data->reqdata.path[1], 0, - NULL); - snprintf((char *)&state->spacket.data[2], - TFTP_BLOCKSIZE, - "%s%c%s%c", filename, '\0', mode, '\0'); - sbytes = 4 + (int)strlen(filename) + (int)strlen(mode); - sbytes = sendto(state->sockfd, (void *)&state->spacket, - sbytes, 0, - state->conn->ip_addr->ai_addr, - state->conn->ip_addr->ai_addrlen); - if(sbytes < 0) { - failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); - } - Curl_safefree(filename); - break; - - case TFTP_EVENT_ACK: /* Connected for transmit */ - infof(data, "%s\n", "Connected for transmit"); - state->state = TFTP_STATE_TX; - tftp_set_timeouts(state); - return tftp_tx(state, event); - - case TFTP_EVENT_DATA: /* connected for receive */ - infof(data, "%s\n", "Connected for receive"); - state->state = TFTP_STATE_RX; - tftp_set_timeouts(state); - return tftp_rx(state, event); - - case TFTP_EVENT_ERROR: - state->state = TFTP_STATE_FIN; - break; - - default: - failf(state->conn->data, "tftp_send_first: internal error\n"); - break; - } - return res; -} - -/********************************************************** - * - * tftp_rx - * - * Event handler for the RX state - * - **********************************************************/ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) -{ - int sbytes; - int rblock; - struct SessionHandle *data = state->conn->data; - - switch(event) { - - case TFTP_EVENT_DATA: - - /* Is this the block we expect? */ - rblock = getrpacketblock(&state->rpacket); - if ((state->block+1) != rblock) { - /* No, log it, up the retry count and fail if over the limit */ - infof(data, - "Received unexpected DATA packet block %d\n", rblock); - state->retries++; - if (state->retries>state->retry_max) { - failf(data, "tftp_rx: giving up waiting for block %d\n", - state->block+1); - return CURLE_TFTP_ILLEGAL; - } - } - /* This is the expected block. Reset counters and ACK it. */ - state->block = (unsigned short)rblock; - state->retries = 0; - setpacketevent(&state->spacket, TFTP_EVENT_ACK); - setpacketblock(&state->spacket, state->block); - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - if(sbytes < 0) { - failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); - } - - /* Check if completed (That is, a less than full packet is received) */ - if (state->rbytes < (int)sizeof(state->spacket)){ - state->state = TFTP_STATE_FIN; - } - else { - state->state = TFTP_STATE_RX; - } - 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\n", state->retries); - if(state->retries > state->retry_max) { - state->error = TFTP_ERR_TIMEOUT; - state->state = TFTP_STATE_FIN; - } - else { - /* Resend the previous ACK */ - sbytes = sendto(state->sockfd, (void *)&state->spacket, - 4, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); - } - } - break; - - case TFTP_EVENT_ERROR: - state->state = TFTP_STATE_FIN; - break; - - default: - failf(data, "%s\n", "tftp_rx: internal error"); - break; - } - Curl_pgrsSetDownloadCounter(data, - (curl_off_t) state->block*TFTP_BLOCKSIZE); - return CURLE_OK; -} - -/********************************************************** - * - * tftp_tx - * - * Event handler for the TX state - * - **********************************************************/ -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) -{ - struct SessionHandle *data = state->conn->data; - int sbytes; - int rblock; - CURLcode res = CURLE_OK; - - switch(event) { - - case TFTP_EVENT_ACK: - /* Ack the packet */ - rblock = getrpacketblock(&state->rpacket); - - if(rblock != state->block) { - /* This isn't the expected block. Log it and up the retry counter */ - infof(data, "Received ACK for block %d, expecting %d\n", - rblock, state->block); - state->retries++; - /* Bail out if over the maximum */ - if(state->retries>state->retry_max) { - failf(data, "tftp_tx: giving up waiting for block %d ack", - state->block); - res = CURLE_SEND_ERROR; - } - else { - /* Re-send the data packet */ - sbytes = sendto(state->sockfd, (void *)&state->spacket, - 4+state->sbytes, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); - res = CURLE_SEND_ERROR; - } - } - return res; - } - /* This is the expected packet. Reset the counters and send the next - block */ - state->block++; - state->retries = 0; - setpacketevent(&state->spacket, TFTP_EVENT_DATA); - setpacketblock(&state->spacket, state->block); - if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) { - state->state = TFTP_STATE_FIN; - return CURLE_OK; - } - res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes); - if(res) - return res; - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4+state->sbytes, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); - } - break; - - case TFTP_EVENT_TIMEOUT: - /* Increment the retry counter and log the timeout */ - state->retries++; - infof(data, "Timeout waiting for block %d ACK. " - " Retries = %d\n", state->retries); - /* Decide if we've had enough */ - if(state->retries > state->retry_max) { - state->error = TFTP_ERR_TIMEOUT; - state->state = TFTP_STATE_FIN; - } else { - /* Re-send the data packet */ - sbytes = sendto(state->sockfd, (void *)&state->spacket, - 4+state->sbytes, SEND_4TH_ARG, - (struct sockaddr *)&state->remote_addr, - state->remote_addrlen); - /* Check all sbytes were sent */ - if(sbytes<0) { - failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); - } - } - break; - - case TFTP_EVENT_ERROR: - state->state = TFTP_STATE_FIN; - break; - - default: - failf(data, "%s\n", "tftp_tx: internal error"); - break; - } - - /* Update the progress meter */ - Curl_pgrsSetUploadCounter(data, (curl_off_t) state->block*TFTP_BLOCKSIZE); - - return res; -} - -/********************************************************** - * - * tftp_state_machine - * - * The tftp state machine event dispatcher - * - **********************************************************/ -static CURLcode tftp_state_machine(tftp_state_data_t *state, - tftp_event_t event) -{ - CURLcode res = CURLE_OK; - struct SessionHandle *data = state->conn->data; - switch(state->state) { - case TFTP_STATE_START: - DEBUGF(infof(data, "TFTP_STATE_START\n")); - res = tftp_send_first(state, event); - break; - case TFTP_STATE_RX: - DEBUGF(infof(data, "TFTP_STATE_RX\n")); - res = tftp_rx(state, event); - break; - case TFTP_STATE_TX: - DEBUGF(infof(data, "TFTP_STATE_TX\n")); - res = tftp_tx(state, event); - break; - case TFTP_STATE_FIN: - infof(data, "%s\n", "TFTP finished"); - break; - default: - DEBUGF(infof(data, "STATE: %d\n", state->state)); - failf(data, "%s\n", "Internal state machine error"); - res = CURLE_TFTP_ILLEGAL; - break; - } - return res; -} - - -/********************************************************** - * - * Curl_tftp_connect - * - * The connect callback - * - **********************************************************/ -CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) -{ - CURLcode code; - tftp_state_data_t *state; - int rc; - - state = conn->data->reqdata.proto.tftp = calloc(sizeof(tftp_state_data_t), - 1); - if(!state) - return CURLE_OUT_OF_MEMORY; - - conn->bits.close = FALSE; /* keep it open if possible */ - - state->conn = conn; - state->sockfd = state->conn->sock[FIRSTSOCKET]; - state->state = TFTP_STATE_START; - - ((struct sockaddr *)&state->local_addr)->sa_family = - conn->ip_addr->ai_family; - - tftp_set_timeouts(state); - - if(!conn->bits.reuse) { - /* If not reused, bind to any interface, random UDP port. If it is reused, - * this has already been done! - * - * We once used the size of the local_addr struct as the third argument for - * bind() to better work with IPv6 or whatever size the struct could have, - * but we learned that at least Tru64, AIX and IRIX *requires* the size of - * that argument to match the exact size of a 'sockaddr_in' struct when - * running IPv4-only. - * - * Therefore we use the size from the address we connected to, which we - * assume uses the same IP version and thus hopefully this works for both - * IPv4 and IPv6... - */ - rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, - conn->ip_addr->ai_addrlen); - if(rc) { - failf(conn->data, "bind() failed; %s\n", - Curl_strerror(conn, Curl_sockerrno())); - return CURLE_COULDNT_CONNECT; - } - } - - Curl_pgrsStartNow(conn->data); - - *done = TRUE; - code = CURLE_OK; - return(code); -} - -/********************************************************** - * - * Curl_tftp_done - * - * The done callback - * - **********************************************************/ -CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status, - bool premature) -{ - (void)status; /* unused */ - (void)premature; /* not used */ - -#if 0 - free(conn->data->reqdata.proto.tftp); - conn->data->reqdata.proto.tftp = NULL; -#endif - Curl_pgrsDone(conn); - - return CURLE_OK; -} - - -/********************************************************** - * - * Curl_tftp - * - * The do callback - * - * This callback handles the entire TFTP transfer - * - **********************************************************/ - -CURLcode Curl_tftp(struct connectdata *conn, bool *done) -{ - struct SessionHandle *data = conn->data; - tftp_state_data_t *state = - (tftp_state_data_t *) conn->data->reqdata.proto.tftp; - tftp_event_t event; - CURLcode code; - int rc; - struct Curl_sockaddr_storage fromaddr; - socklen_t fromlen; - int check_time = 0; - - *done = TRUE; - - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct TFTP' to play with. For new connections, - the struct TFTP is allocated and setup in the Curl_tftp_connect() function. - */ - if(!state) { - code = Curl_tftp_connect(conn, done); - if(code) - return code; - state = (tftp_state_data_t *)conn->data->reqdata.proto.tftp; - } - - /* Run the TFTP State Machine */ - for(tftp_state_machine(state, TFTP_EVENT_INIT); - state->state != TFTP_STATE_FIN; - tftp_state_machine(state, event) ) { - - /* Wait until ready to read or timeout occurs */ - rc=Curl_select(state->sockfd, CURL_SOCKET_BAD, state->retry_time * 1000); - - if(rc == -1) { - /* bail out */ - int error = Curl_sockerrno(); - failf(data, "%s\n", Curl_strerror(conn, error)); - event = TFTP_EVENT_ERROR; - } - else if (rc==0) { - /* A timeout occured */ - event = TFTP_EVENT_TIMEOUT; - - /* Force a look at transfer timeouts */ - check_time = 0; - - } - else { - - /* Receive the packet */ - fromlen=sizeof(fromaddr); - state->rbytes = recvfrom(state->sockfd, - (void *)&state->rpacket, sizeof(state->rpacket), - 0, (struct sockaddr *)&fromaddr, &fromlen); - if(state->remote_addrlen==0) { - memcpy(&state->remote_addr, &fromaddr, fromlen); - state->remote_addrlen = fromlen; - } - - /* Sanity check packet length */ - if (state->rbytes < 4) { - failf(conn->data, "Received too short packet\n"); - /* Not a timeout, but how best to handle it? */ - event = TFTP_EVENT_TIMEOUT; - } - else { - - /* The event is given by the TFTP packet time */ - event = (tftp_event_t)getrpacketevent(&state->rpacket); - - switch(event) { - case TFTP_EVENT_DATA: - /* Don't pass to the client empty or retransmitted packets */ - if (state->rbytes > 4 && - ((state->block+1) == getrpacketblock(&state->rpacket))) { - code = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)&state->rpacket.data[4], - state->rbytes-4); - if(code) - return code; - } - break; - case TFTP_EVENT_ERROR: - state->error = (tftp_error_t)getrpacketblock(&state->rpacket); - infof(conn->data, "%s\n", (char *)&state->rpacket.data[4]); - break; - case TFTP_EVENT_ACK: - break; - case TFTP_EVENT_RRQ: - case TFTP_EVENT_WRQ: - default: - failf(conn->data, "%s\n", "Internal error: Unexpected packet"); - break; - } - - /* Update the progress meter */ - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - } - } - - /* Check for transfer timeout every 10 blocks, or after timeout */ - if(check_time%10==0) { - time_t current; - time(¤t); - if(current>state->max_time) { - DEBUGF(infof(data, "timeout: %d > %d\n", - current, state->max_time)); - state->error = TFTP_ERR_TIMEOUT; - state->state = TFTP_STATE_FIN; - } - } - - } - - /* Tell curl we're done */ - code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - if(code) - return code; - - /* If we have encountered an error */ - if(state->error) { - - /* Translate internal error codes to curl error codes */ - switch(state->error) { - case TFTP_ERR_NOTFOUND: - code = CURLE_TFTP_NOTFOUND; - break; - case TFTP_ERR_PERM: - code = CURLE_TFTP_PERM; - break; - case TFTP_ERR_DISKFULL: - code = CURLE_TFTP_DISKFULL; - break; - case TFTP_ERR_ILLEGAL: - code = CURLE_TFTP_ILLEGAL; - break; - case TFTP_ERR_UNKNOWNID: - code = CURLE_TFTP_UNKNOWNID; - break; - case TFTP_ERR_EXISTS: - code = CURLE_TFTP_EXISTS; - break; - case TFTP_ERR_NOSUCHUSER: - code = CURLE_TFTP_NOSUCHUSER; - break; - case TFTP_ERR_TIMEOUT: - code = CURLE_OPERATION_TIMEOUTED; - break; - case TFTP_ERR_NORESPONSE: - code = CURLE_COULDNT_CONNECT; - break; - default: - code= CURLE_ABORTED_BY_CALLBACK; - break; - } - } - else - code = CURLE_OK; - return code; -} -#endif diff --git a/Utilities/cmcurl/tftp.h b/Utilities/cmcurl/tftp.h deleted file mode 100644 index c712541..0000000 --- a/Utilities/cmcurl/tftp.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __TFTP_H -#define __TFTP_H - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -#ifndef CURL_DISABLE_TFTP -CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done); -CURLcode Curl_tftp(struct connectdata *conn, bool *done); -CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode, bool premature); -#endif -#endif diff --git a/Utilities/cmcurl/timeval.c b/Utilities/cmcurl/timeval.c deleted file mode 100644 index bb9c0a1..0000000 --- a/Utilities/cmcurl/timeval.c +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "timeval.h" - -#ifndef HAVE_GETTIMEOFDAY - -#ifdef WIN32 -#include - -static int gettimeofday(struct timeval *tp, void *nothing) -{ -#ifdef WITHOUT_MM_LIB - SYSTEMTIME st; - time_t tt; - struct tm tmtm; - /* mktime converts local to UTC */ - GetLocalTime (&st); - tmtm.tm_sec = st.wSecond; - tmtm.tm_min = st.wMinute; - tmtm.tm_hour = st.wHour; - tmtm.tm_mday = st.wDay; - tmtm.tm_mon = st.wMonth - 1; - tmtm.tm_year = st.wYear - 1900; - tmtm.tm_isdst = -1; - tt = mktime (&tmtm); - tp->tv_sec = tt; - tp->tv_usec = st.wMilliseconds * 1000; -#else - /** - ** The earlier time calculations using GetLocalTime - ** had a time resolution of 10ms.The timeGetTime, part - ** of multimedia apis offer a better time resolution - ** of 1ms.Need to link against winmm.lib for this - **/ - unsigned long Ticks = 0; - unsigned long Sec =0; - unsigned long Usec = 0; - Ticks = timeGetTime(); - - Sec = Ticks/1000; - Usec = (Ticks - (Sec*1000))*1000; - tp->tv_sec = Sec; - tp->tv_usec = Usec; -#endif /* WITHOUT_MM_LIB */ - (void)nothing; - return 0; -} -#else /* WIN32 */ -/* non-win32 version of Curl_gettimeofday() */ -static int gettimeofday(struct timeval *tp, void *nothing) -{ - (void)nothing; /* we don't support specific time-zones */ - tp->tv_sec = (long)time(NULL); - tp->tv_usec = 0; - return 0; -} -#endif /* WIN32 */ -#endif /* HAVE_GETTIMEOFDAY */ - -/* Return the current time in a timeval struct */ -struct timeval curlx_tvnow(void) -{ - struct timeval now; - (void)gettimeofday(&now, NULL); - return now; -} - -/* - * Make sure that the first argument is the more recent time, as otherwise - * we'll get a weird negative time-diff back... - * - * Returns: the time difference in number of milliseconds. - */ -long curlx_tvdiff(struct timeval newer, struct timeval older) -{ - return (newer.tv_sec-older.tv_sec)*1000+ - (newer.tv_usec-older.tv_usec)/1000; -} - -/* - * Same as curlx_tvdiff but with full usec resolution. - * - * Returns: the time difference in seconds with subsecond resolution. - */ -double curlx_tvdiff_secs(struct timeval newer, struct timeval older) -{ - return (double)(newer.tv_sec-older.tv_sec)+ - (double)(newer.tv_usec-older.tv_usec)/1000000.0; -} - -/* return the number of seconds in the given input timeval struct */ -long Curl_tvlong(struct timeval t1) -{ - return t1.tv_sec; -} diff --git a/Utilities/cmcurl/timeval.h b/Utilities/cmcurl/timeval.h deleted file mode 100644 index effd741..0000000 --- a/Utilities/cmcurl/timeval.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __TIMEVAL_H -#define __TIMEVAL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* - * CAUTION: this header is designed to work when included by the app-side - * as well as the library. Do not mix with library internals! - */ - -#include "setup.h" - -#ifdef HAVE_SYS_TIME_H -#include -#ifdef TIME_WITH_SYS_TIME -#include -#endif -#else -#ifdef HAVE_TIME_H -#include -#endif -#endif - -#ifndef HAVE_STRUCT_TIMEVAL -struct timeval { - long tv_sec; - long tv_usec; -}; -#endif - -struct timeval curlx_tvnow(void); - -/* - * Make sure that the first argument (t1) is the more recent time and t2 is - * the older time, as otherwise you get a weird negative time-diff back... - * - * Returns: the time difference in number of milliseconds. - */ -long curlx_tvdiff(struct timeval t1, struct timeval t2); - -/* - * Same as curlx_tvdiff but with full usec resolution. - * - * Returns: the time difference in seconds with subsecond resolution. - */ -double curlx_tvdiff_secs(struct timeval t1, struct timeval t2); - -long Curl_tvlong(struct timeval t1); - -/* These two defines below exist to provide the older API for library - internals only. */ -#define Curl_tvnow() curlx_tvnow() -#define Curl_tvdiff(x,y) curlx_tvdiff(x,y) -#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y) - -#endif diff --git a/Utilities/cmcurl/transfer.c b/Utilities/cmcurl/transfer.c deleted file mode 100644 index 5cb3361..0000000 --- a/Utilities/cmcurl/transfer.c +++ /dev/null @@ -1,2494 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -#include - -#include "strtoofft.h" -#include "strequal.h" - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#ifndef HAVE_SOCKET -#error "We can't compile without socket() support!" -#endif - -#endif - -#include "urldata.h" -#include -#include "netrc.h" - -#include "content_encoding.h" -#include "hostip.h" -#include "transfer.h" -#include "sendf.h" -#include "speedcheck.h" -#include "progress.h" -#include "http.h" -#include "url.h" -#include "getinfo.h" -#include "sslgen.h" -#include "http_digest.h" -#include "http_ntlm.h" -#include "http_negotiate.h" -#include "share.h" -#include "memory.h" -#include "select.h" -#include "multiif.h" -#include "easyif.h" /* for Curl_convert_to_network prototype */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ -#include "memdebug.h" - -#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */ - -/* - * This function will call the read callback to fill our buffer with data - * to upload. - */ -CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) -{ - struct SessionHandle *data = conn->data; - size_t buffersize = (size_t)bytes; - int nread; - - if(conn->bits.upload_chunky) { - /* if chunked Transfer-Encoding */ - buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */ - data->reqdata.upload_fromhere += 10; /* 32bit hex + CRLF */ - } - - /* this function returns a size_t, so we typecast to int to prevent warnings - with picky compilers */ - nread = (int)conn->fread(data->reqdata.upload_fromhere, 1, - buffersize, conn->fread_in); - - if(nread == CURL_READFUNC_ABORT) { - failf(data, "operation aborted by callback\n"); - return CURLE_ABORTED_BY_CALLBACK; - } - - if(!conn->bits.forbidchunk && conn->bits.upload_chunky) { - /* if chunked Transfer-Encoding */ - char hexbuffer[11]; - int hexlen = snprintf(hexbuffer, sizeof(hexbuffer), - "%x\r\n", nread); - /* move buffer pointer */ - data->reqdata.upload_fromhere -= hexlen; - nread += hexlen; - - /* copy the prefix to the buffer */ - memcpy(data->reqdata.upload_fromhere, hexbuffer, hexlen); - - /* always append CRLF to the data */ - memcpy(data->reqdata.upload_fromhere + nread, "\r\n", 2); - - if((nread - hexlen) == 0) { - /* mark this as done once this chunk is transfered */ - data->reqdata.keep.upload_done = TRUE; - } - - nread+=2; /* for the added CRLF */ - } - - *nreadp = nread; - -#ifdef CURL_DOES_CONVERSIONS - if(data->set.prefer_ascii) { - CURLcode res; - res = Curl_convert_to_network(data, data->reqdata.upload_fromhere, nread); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - return(res); - } - } -#endif /* CURL_DOES_CONVERSIONS */ - - return CURLE_OK; -} - -/* - * checkhttpprefix() - * - * Returns TRUE if member of the list matches prefix of string - */ -static bool -checkhttpprefix(struct SessionHandle *data, - const char *s) -{ - struct curl_slist *head = data->set.http200aliases; - bool rc = FALSE; -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding using a scratch area */ - char *scratch = calloc(1, strlen(s)+1); - if (NULL == scratch) { - failf (data, "Failed to calloc memory for conversion!"); - return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ - } - strcpy(scratch, s); - if (CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { - /* Curl_convert_from_network calls failf if unsuccessful */ - free(scratch); - return FALSE; /* can't return CURLE_foobar so return FALSE */ - } - s = scratch; -#endif /* CURL_DOES_CONVERSIONS */ - - while (head) { - if (checkprefix(head->data, s)) { - rc = TRUE; - break; - } - head = head->next; - } - - if ((rc != TRUE) && (checkprefix("HTTP/", s))) { - rc = TRUE; - } - -#ifdef CURL_DOES_CONVERSIONS - free(scratch); -#endif /* CURL_DOES_CONVERSIONS */ - return rc; -} - -/* - * Curl_readrewind() rewinds the read stream. This typically (so far) only - * used for HTTP POST/PUT with multi-pass authentication when a sending was - * denied and a resend is necessary. - */ -CURLcode Curl_readrewind(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - - conn->bits.rewindaftersend = FALSE; /* we rewind now */ - - /* We have sent away data. If not using CURLOPT_POSTFIELDS or - CURLOPT_HTTPPOST, call app to rewind - */ - if(data->set.postfields || - (data->set.httpreq == HTTPREQ_POST_FORM)) - ; /* do nothing */ - else { - if(data->set.ioctl) { - curlioerr err; - - err = (data->set.ioctl) (data, CURLIOCMD_RESTARTREAD, - data->set.ioctl_client); - infof(data, "the ioctl callback returned %d\n", (int)err); - - if(err) { - /* FIXME: convert to a human readable error message */ - failf(data, "ioctl callback returned error %d\n", (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 - ourself with fseek() */ - if(data->set.fread == (curl_read_callback)fread) { - if(-1 != fseek(data->set.in, 0, SEEK_SET)) - /* successful rewind */ - return CURLE_OK; - } - - /* no callback set or failure aboe, makes us fail at once */ - failf(data, "necessary data rewind wasn't possible\n"); - return CURLE_SEND_FAIL_REWIND; - } - } - return CURLE_OK; -} - -static int data_pending(struct connectdata *conn) -{ - return Curl_ssl_data_pending(conn, FIRSTSOCKET); -} - -#ifndef MIN -#define MIN(a,b) (a < b ? a : b) -#endif - -static void read_rewind(struct connectdata *conn, - size_t thismuch) -{ - conn->read_pos -= thismuch; - conn->bits.stream_was_rewound = TRUE; - -#ifdef CURLDEBUG - { - char buf[512 + 1]; - size_t show; - - show = MIN(conn->buf_len - conn->read_pos, sizeof(buf)-1); - memcpy(buf, conn->master_buffer + conn->read_pos, show); - buf[show] = '\0'; - - DEBUGF(infof(conn->data, - "Buffer after stream rewind (read_pos = %d): [%s]", - conn->read_pos, buf)); - } -#endif -} - -/* - * Curl_readwrite() is the low-level function to be called when data is to - * be read and written to/from the connection. - */ -CURLcode Curl_readwrite(struct connectdata *conn, - bool *done) -{ - struct SessionHandle *data = conn->data; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - CURLcode result; - ssize_t nread; /* number of bytes read */ - int didwhat=0; - - curl_socket_t fd_read; - curl_socket_t fd_write; - int select_res; - - curl_off_t contentlength; - - /* 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_READ|KEEP_READ_HOLD)) == KEEP_READ) - fd_read = conn->sockfd; - else - fd_read = CURL_SOCKET_BAD; - - if((k->keepon & (KEEP_WRITE|KEEP_WRITE_HOLD)) == KEEP_WRITE) - fd_write = conn->writesockfd; - else - fd_write = CURL_SOCKET_BAD; - - select_res = Curl_select(fd_read, fd_write, 0); - if(select_res == CSELECT_ERR) { - failf(data, "select/poll returned error"); - return CURLE_SEND_ERROR; - } - - do { - /* 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_READ) && - ((select_res & CSELECT_IN) || conn->bits.stream_was_rewound)) { - /* read */ - bool is_empty_data = FALSE; - - /* This is where we loop until we have read everything there is to - read or we get a EWOULDBLOCK */ - do { - size_t buffersize = data->set.buffer_size? - data->set.buffer_size : BUFSIZE; - size_t bytestoread = buffersize; - int readrc; - - if (k->size != -1 && !k->header) { - /* make sure we don't read "too much" if we can help it since we - might be pipelining and then someone else might want to read what - follows! */ - curl_off_t totalleft = k->size - k->bytecount; - if(totalleft < (curl_off_t)bytestoread) - bytestoread = (size_t)totalleft; - } - - /* receive data from the network! */ - readrc = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread); - - /* subzero, this would've blocked */ - if(0 > readrc) - break; /* get out of loop */ - - /* get the CURLcode from the int */ - result = (CURLcode)readrc; - - if(result>0) - return result; - - if ((k->bytecount == 0) && (k->writebytecount == 0)) { - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - if(k->wait100_after_headers) - /* set time stamp to compare with when waiting for the 100 */ - k->start100 = Curl_tvnow(); - } - - didwhat |= KEEP_READ; - /* indicates data of zero size, i.e. empty file */ - is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0)); - - /* NULL terminate, allowing string ops to be used */ - if (0 < nread || is_empty_data) { - k->buf[nread] = 0; - } - else if (0 >= nread) { - /* if we receive 0 or less here, the server closed the connection - and we bail out from this! */ - - k->keepon &= ~KEEP_READ; - break; - } - - /* Default buffer to use when we write the buffer, it may be changed - in the flow below before the actual storing is done. */ - k->str = k->buf; - - /* Since this is a two-state thing, we check if we are parsing - headers at the moment or not. */ - if (k->header) { - /* we are in parse-the-header-mode */ - bool stop_reading = FALSE; - - /* header line within buffer loop */ - do { - size_t hbufp_index; - size_t rest_length; - size_t full_length; - int writetype; - - /* str_start is start of line within buf */ - k->str_start = k->str; - - /* data is in network encoding so use 0x0a instead of '\n' */ - k->end_ptr = memchr(k->str_start, 0x0a, nread); - - if (!k->end_ptr) { - /* Not a complete header line within buffer, append the data to - the end of the headerbuff. */ - - if (k->hbuflen + nread >= data->state.headersize) { - /* We enlarge the header buffer as it is too small */ - char *newbuff; - size_t newsize=CURLMAX((k->hbuflen+nread)*3/2, - data->state.headersize*2); - hbufp_index = k->hbufp - data->state.headerbuff; - newbuff = (char *)realloc(data->state.headerbuff, newsize); - if(!newbuff) { - failf (data, "Failed to alloc memory for big header!"); - return CURLE_OUT_OF_MEMORY; - } - data->state.headersize=newsize; - data->state.headerbuff = newbuff; - k->hbufp = data->state.headerbuff + hbufp_index; - } - memcpy(k->hbufp, k->str, nread); - k->hbufp += nread; - k->hbuflen += nread; - if (!k->headerline && (k->hbuflen>5)) { - /* make a first check that this looks like a HTTP header */ - if(!checkhttpprefix(data, data->state.headerbuff)) { - /* this is not the beginning of a HTTP first header line */ - k->header = FALSE; - k->badheader = HEADER_ALLBAD; - break; - } - } - - break; /* read more and try again */ - } - - /* decrease the size of the remaining (supposed) header line */ - rest_length = (k->end_ptr - k->str)+1; - nread -= (ssize_t)rest_length; - - k->str = k->end_ptr + 1; /* move past new line */ - - full_length = k->str - k->str_start; - - /* - * We're about to copy a chunk of data to the end of the - * already received header. We make sure that the full string - * fit in the allocated header buffer, or else we enlarge - * it. - */ - if (k->hbuflen + full_length >= - data->state.headersize) { - char *newbuff; - size_t newsize=CURLMAX((k->hbuflen+full_length)*3/2, - data->state.headersize*2); - hbufp_index = k->hbufp - data->state.headerbuff; - newbuff = (char *)realloc(data->state.headerbuff, newsize); - if(!newbuff) { - failf (data, "Failed to alloc memory for big header!"); - return CURLE_OUT_OF_MEMORY; - } - data->state.headersize= newsize; - data->state.headerbuff = newbuff; - k->hbufp = data->state.headerbuff + hbufp_index; - } - - /* copy to end of line */ - memcpy(k->hbufp, k->str_start, full_length); - k->hbufp += full_length; - k->hbuflen += full_length; - *k->hbufp = 0; - k->end_ptr = k->hbufp; - - k->p = data->state.headerbuff; - - /**** - * We now have a FULL header line that p points to - *****/ - - if(!k->headerline) { - /* the first read header */ - if((k->hbuflen>5) && - !checkhttpprefix(data, data->state.headerbuff)) { - /* this is not the beginning of a HTTP first header line */ - k->header = FALSE; - if(nread) - /* since there's more, this is a partial bad header */ - k->badheader = HEADER_PARTHEADER; - else { - /* this was all we read so its all a bad header */ - k->badheader = HEADER_ALLBAD; - nread = (ssize_t)rest_length; - } - break; - } - } - - /* headers are in network encoding so - use 0x0a and 0x0d instead of '\n' and '\r' */ - if ((0x0a == *k->p) || (0x0d == *k->p)) { - size_t headerlen; - /* Zero-length header line means end of headers! */ - -#ifdef CURL_DOES_CONVERSIONS - if (0x0d == *k->p) { - *k->p = '\r'; /* replace with CR in host encoding */ - k->p++; /* pass the CR byte */ - } - if (0x0a == *k->p) { - *k->p = '\n'; /* replace with LF in host encoding */ - k->p++; /* pass the LF byte */ - } -#else - if ('\r' == *k->p) - k->p++; /* pass the \r byte */ - if ('\n' == *k->p) - k->p++; /* pass the \n byte */ -#endif /* CURL_DOES_CONVERSIONS */ - - if(100 == k->httpcode) { - /* - * We have made a 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->write_after_100_header) { - - k->write_after_100_header = FALSE; - k->keepon |= KEEP_WRITE; - } - } - else { - k->header = FALSE; /* no more header to parse! */ - - if((k->size == -1) && !conn->bits.chunk && !conn->bits.close) - /* When connection is not to get closed, but no - Content-Length nor Content-Encoding chunked have been - received, there is no body in this response. We don't set - stop_reading TRUE since that would also prevent necessary - authentication actions to take place. */ - conn->bits.no_body = TRUE; - - } - - if (417 == k->httpcode) { - /* - * we got: "417 Expectation Failed" this means: - * we have made a HTTP call and our Expect Header - * seems to cause a problem => abort the write operations - * (or prevent them from starting). - */ - k->write_after_100_header = FALSE; - k->keepon &= ~KEEP_WRITE; - } - -#ifndef CURL_DISABLE_HTTP - /* - * When all the headers have been parsed, see if we should give - * up and return an error. - */ - if (Curl_http_should_fail(conn)) { - failf (data, "The requested URL returned error: %d", - k->httpcode); - return CURLE_HTTP_RETURNED_ERROR; - } -#endif /* CURL_DISABLE_HTTP */ - - /* now, only output this if the header AND body are requested: - */ - writetype = CLIENTWRITE_HEADER; - if (data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - headerlen = k->p - data->state.headerbuff; - - result = Curl_client_write(conn, writetype, - data->state.headerbuff, - headerlen); - if(result) - return result; - - data->info.header_size += (long)headerlen; - conn->headerbytecount += (long)headerlen; - - conn->deductheadercount = - (100 == k->httpcode)?conn->headerbytecount:0; - - if (data->reqdata.resume_from && - (data->set.httpreq==HTTPREQ_GET) && - (k->httpcode == 416)) { - /* "Requested Range Not Satisfiable" */ - stop_reading = TRUE; - } - -#ifndef CURL_DISABLE_HTTP - if(!stop_reading) { - /* 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 metod was picked. */ - result = Curl_http_auth_act(conn); - - if(result) - return result; - - if(conn->bits.rewindaftersend) { - /* We rewind after a complete send, so thus we continue - sending now */ - infof(data, "Keep sending data to get tossed away!\n"); - k->keepon |= KEEP_WRITE; - } - } -#endif /* CURL_DISABLE_HTTP */ - - 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(conn->bits.no_body) - stop_reading = TRUE; - else { - /* If we know the expected size of this document, we set the - maximum download size to the size of the expected - document or else, we won't know when to stop reading! - - Note that we set the download maximum even if we read a - "Connection: close" header, to make sure that - "Content-Length: 0" still prevents us from attempting to - read the (missing) response-body. - */ - /* According to RFC2616 section 4.4, we MUST ignore - Content-Length: headers if we are now receiving data - using chunked Transfer-Encoding. - */ - if(conn->bits.chunk) - k->size=-1; - - } - if(-1 != k->size) { - /* We do this operation even if no_body is true, since this - data might be retrieved later with curl_easy_getinfo() - and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */ - - Curl_pgrsSetDownloadSize(data, k->size); - k->maxdownload = k->size; - } - /* If max download size is *zero* (nothing) we already - have nothing and can safely return ok now! */ - if(0 == k->maxdownload) - stop_reading = TRUE; - - if(stop_reading) { - /* we make sure that this socket isn't read more now */ - k->keepon &= ~KEEP_READ; - } - - break; /* exit header line loop */ - } - - /* We continue reading headers, so reset the line-based - header parsing variables hbufp && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; - continue; - } - - /* - * Checks for special headers coming up. - */ - - 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! */ - int httpversion_major; - int nc; -#ifdef CURL_DOES_CONVERSIONS -#define HEADER1 scratch -#define SCRATCHSIZE 21 - CURLcode res; - char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */ - /* We can't really convert this yet because we - don't know if it's the 1st header line or the body. - So we do a partial conversion into a scratch area, - leaving the data at k->p as-is. - */ - strncpy(&scratch[0], k->p, SCRATCHSIZE); - scratch[SCRATCHSIZE] = 0; /* null terminate */ - res = Curl_convert_from_network(data, - &scratch[0], - SCRATCHSIZE); - if (CURLE_OK != res) { - /* Curl_convert_from_network calls failf if unsuccessful */ - return res; - } -#else -#define HEADER1 k->p /* no conversion needed, just use k->p */ -#endif /* CURL_DOES_CONVERSIONS */ - - nc = sscanf(HEADER1, - " HTTP/%d.%d %3d", - &httpversion_major, - &k->httpversion, - &k->httpcode); - if (nc==3) { - k->httpversion += 10 * httpversion_major; - } - else { - /* this is the real world, not a Nirvana - NCSA 1.5.x returns this crap when asked for HTTP/1.1 - */ - nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); - k->httpversion = 10; - - /* If user has set option HTTP200ALIASES, - compare header line against list of aliases - */ - if (!nc) { - if (checkhttpprefix(data, k->p)) { - nc = 1; - k->httpcode = 200; - k->httpversion = - (data->set.httpversion==CURL_HTTP_VERSION_1_0)? 10 : 11; - } - } - } - - if (nc) { - data->info.httpcode = k->httpcode; - data->info.httpversion = k->httpversion; - - /* - * 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 - * are definitely errors, so give up here. - */ - if (data->set.http_fail_on_error && (k->httpcode >= 400) && - ((k->httpcode != 401) || !data->set.userpwd) && - ((k->httpcode != 407) || !data->set.proxyuserpwd) ) { - - if (data->reqdata.resume_from && - (data->set.httpreq==HTTPREQ_GET) && - (k->httpcode == 416)) { - /* "Requested Range Not Satisfiable", just proceed and - pretend this is no error */ - } - else { - /* serious error, go home! */ - failf (data, "The requested URL returned error: %d", - k->httpcode); - return CURLE_HTTP_RETURNED_ERROR; - } - } - - if(k->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! */ - conn->bits.close = TRUE; - - switch(k->httpcode) { - case 204: - /* (quote from RFC2616, section 10.2.5): The server has - * fulfilled the request but does not need to return an - * entity-body ... The 204 response MUST NOT include a - * message-body, and thus is always terminated by the first - * empty line after the header fields. */ - /* FALLTHROUGH */ - case 416: /* Requested Range Not Satisfiable, it has the - Content-Length: set as the "real" document but no - actual response is sent. */ - case 304: - /* (quote from RFC2616, section 10.3.5): The 304 response - * MUST NOT contain a message-body, and thus is always - * terminated by the first empty line after the header - * fields. */ - k->size=0; - k->maxdownload=0; - k->ignorecl = TRUE; /* ignore Content-Length headers */ - break; - default: - /* nothing */ - break; - } - } - else { - k->header = FALSE; /* this is not a header line */ - break; - } - } - -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding */ - result = Curl_convert_from_network(data, k->p, strlen(k->p)); - if (CURLE_OK != result) { - return(result); - } - /* Curl_convert_from_network calls failf if unsuccessful */ -#endif /* CURL_DOES_CONVERSIONS */ - - /* Check for Content-Length: header lines to get size. Ignore - the header completely if we get a 416 response as then we're - resuming a document that we don't get, and this header contains - info about the true size of the document we didn't get now. */ - if (!k->ignorecl && !data->set.ignorecl && - checkprefix("Content-Length:", k->p)) { - contentlength = curlx_strtoofft(k->p+15, NULL, 10); - if (data->set.max_filesize && - contentlength > data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - if(contentlength >= 0) { - k->size = contentlength; - k->maxdownload = k->size; - } - else { - /* Negative Content-Length is really odd, and we know it - happens for example when older Apache servers send large - files */ - conn->bits.close = TRUE; - infof(data, "Negative content-length: %" FORMAT_OFF_T - ", closing after transfer\n", contentlength); - } - } - /* check for Content-Type: header lines to get the mime-type */ - else if (checkprefix("Content-Type:", k->p)) { - char *start; - char *end; - size_t len; - - /* Find the first non-space letter */ - for(start=k->p+13; - *start && ISSPACE(*start); - start++) - ; /* empty loop */ - - /* data is now in the host encoding so - use '\r' and '\n' instead of 0x0d and 0x0a */ - end = strchr(start, '\r'); - if(!end) - end = strchr(start, '\n'); - - if(end) { - /* skip all trailing space letters */ - for(; ISSPACE(*end) && (end > start); end--) - ; /* empty loop */ - - /* get length of the type */ - len = end-start+1; - - /* allocate memory of a cloned copy */ - Curl_safefree(data->info.contenttype); - - data->info.contenttype = malloc(len + 1); - if (NULL == data->info.contenttype) - return CURLE_OUT_OF_MEMORY; - - /* copy the content-type string */ - memcpy(data->info.contenttype, start, len); - data->info.contenttype[len] = 0; /* zero terminate */ - } - } -#ifndef CURL_DISABLE_HTTP - else if((k->httpversion == 10) && - conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "keep-alive")) { - /* - * When a 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. - */ - conn->bits.close = FALSE; /* don't close when done */ - infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); - } - else if((k->httpversion == 11) && - conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "close")) { - /* - * We get a HTTP/1.1 response from a proxy and it says it'll - * close down after this transfer. - */ - conn->bits.close = TRUE; /* close when done */ - infof(data, "HTTP/1.1 proxy connection set close!\n"); - } - else if((k->httpversion == 10) && - Curl_compareheader(k->p, "Connection:", "keep-alive")) { - /* - * A 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] */ - conn->bits.close = FALSE; /* don't close when done */ - infof(data, "HTTP/1.0 connection set to keep alive!\n"); - } - else if (Curl_compareheader(k->p, "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. - */ - conn->bits.close = TRUE; /* close when done */ - } - else if (Curl_compareheader(k->p, - "Transfer-Encoding:", "chunked")) { - /* - * [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. */ - conn->bits.chunk = TRUE; /* chunks coming our way */ - - /* init our chunky engine */ - Curl_httpchunk_init(conn); - } - - else if (checkprefix("Trailer:", k->p) || - checkprefix("Trailers:", k->p)) { - /* - * This test helps Curl_httpchunk_read() to determine to look - * for well formed trailers after the zero chunksize record. In - * this case a CRLF is required after the zero chunksize record - * when no trailers are sent, or after the last trailer record. - * - * It seems both Trailer: and Trailers: occur in the wild. - */ - conn->bits.trailerHdrPresent = TRUE; - } - - else if (checkprefix("Content-Encoding:", k->p) && - data->set.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 - */ - char *start; - - /* Find the first non-space letter */ - for(start=k->p+17; - *start && ISSPACE(*start); - start++) - ; /* empty loop */ - - /* Record the content-encoding for later use */ - if (checkprefix("identity", start)) - k->content_encoding = IDENTITY; - else if (checkprefix("deflate", start)) - k->content_encoding = DEFLATE; - else if (checkprefix("gzip", start) - || checkprefix("x-gzip", start)) - k->content_encoding = GZIP; - else if (checkprefix("compress", start) - || checkprefix("x-compress", start)) - k->content_encoding = COMPRESS; - } - else if (checkprefix("Content-Range:", k->p)) { - /* Content-Range: bytes [num]- - Content-Range: bytes: [num]- - Content-Range: [num]- - - 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! - */ - - char *ptr = k->p + 14; - - /* Move forward until first digit */ - while(*ptr && !ISDIGIT(*ptr)) - ptr++; - - k->offset = curlx_strtoofft(ptr, NULL, 10); - - if (data->reqdata.resume_from == k->offset) - /* we asked for a resume and we got it */ - k->content_range = TRUE; - } -#if !defined(CURL_DISABLE_COOKIES) - else if(data->cookies && - checkprefix("Set-Cookie:", k->p)) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, - CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_add(data, - data->cookies, TRUE, k->p+11, - /* If there is a custom-set Host: name, use it - here, or else use real peer host name. */ - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:conn->host.name, - data->reqdata.path); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } -#endif - else if(checkprefix("Last-Modified:", k->p) && - (data->set.timecondition || data->set.get_filetime) ) { - time_t secs=time(NULL); - k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"), - &secs); - if(data->set.get_filetime) - data->info.filetime = (long)k->timeofdoc; - } - else if((checkprefix("WWW-Authenticate:", k->p) && - (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", k->p) && - (407 == k->httpcode))) { - result = Curl_http_input_auth(conn, k->httpcode, k->p); - if(result) - return result; - } - else if ((k->httpcode >= 300 && k->httpcode < 400) && - checkprefix("Location:", k->p)) { - if(data->set.http_follow_location) { - /* this is the URL that the server advices us to get instead */ - char *ptr; - char *start=k->p; - char backup; - - start += 9; /* pass "Location:" */ - - /* Skip spaces and tabs. We do this to support multiple - white spaces after the "Location:" keyword. */ - while(*start && ISSPACE(*start )) - start++; - - /* Scan through the string from the end to find the last - non-space. k->end_ptr points to the actual terminating zero - letter, move pointer one letter back and start from - there. This logic strips off trailing whitespace, but keeps - any embedded whitespace. */ - ptr = k->end_ptr-1; - while((ptr>=start) && ISSPACE(*ptr)) - ptr--; - ptr++; - - backup = *ptr; /* store the ending letter */ - if(ptr != start) { - *ptr = '\0'; /* zero terminate */ - data->reqdata.newurl = strdup(start); /* clone string */ - *ptr = backup; /* restore ending letter */ - if(!data->reqdata.newurl) - return CURLE_OUT_OF_MEMORY; - } - } - } -#endif /* CURL_DISABLE_HTTP */ - - /* - * End of header-checks. Write them to the client. - */ - - writetype = CLIENTWRITE_HEADER; - if (data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - k->p, (size_t)k->hbuflen, conn); - - result = Curl_client_write(conn, writetype, k->p, k->hbuflen); - if(result) - return result; - - data->info.header_size += (long)k->hbuflen; - conn->headerbytecount += (long)k->hbuflen; - - /* reset hbufp pointer && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; - } - while (!stop_reading && *k->str); /* header line within buffer */ - - if(stop_reading) - /* We've stopped dealing with input, get out of the do-while loop */ - break; - - /* 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. */ - - } /* end if header mode */ - - /* 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->str && !k->header && (nread > 0 || is_empty_data)) { - - 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->protocol&PROT_HTTP) { - /* HTTP-only checks */ - - if (data->reqdata.newurl) { - if(conn->bits.close) { - /* Abort after the headers if "follow Location" is set - and we're set to close anyway. */ - k->keepon &= ~KEEP_READ; - *done = TRUE; - return CURLE_OK; - } - /* We have a new url to load, but since we want to be able - to re-use this connection properly, we read the full - response in "ignore more" */ - k->ignorebody = TRUE; - infof(data, "Ignoring the response-body\n"); - } - if (data->reqdata.resume_from && !k->content_range && - (data->set.httpreq==HTTPREQ_GET) && - !k->ignorebody) { - /* 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 doesn't seem to support " - "byte ranges. Cannot resume."); - return CURLE_HTTP_RANGE_ERROR; - } - - if(data->set.timecondition && !data->reqdata.range) { - /* A time condition has been set AND no ranges have been - requested. This seems to be what chapter 13.3.4 of - RFC 2616 defines to be the correct action for a - HTTP/1.1 client */ - if((k->timeofdoc > 0) && (data->set.timevalue > 0)) { - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - if(k->timeofdoc < data->set.timevalue) { - infof(data, - "The requested document is not new enough\n"); - *done = TRUE; - return CURLE_OK; - } - break; - case CURL_TIMECOND_IFUNMODSINCE: - if(k->timeofdoc > data->set.timevalue) { - infof(data, - "The requested document is not old enough\n"); - *done = TRUE; - return CURLE_OK; - } - break; - } /* switch */ - } /* two valid time strings */ - } /* we have a time condition */ - - } /* this is HTTP */ - } /* this is the first time we write a body part */ - k->bodywrites++; - - /* pass data to the debug function before it gets "dechunked" */ - if(data->set.verbose) { - if(k->badheader) { - Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff, - (size_t)k->hbuflen, conn); - if(k->badheader == HEADER_PARTHEADER) - Curl_debug(data, CURLINFO_DATA_IN, - k->str, (size_t)nread, conn); - } - else - Curl_debug(data, CURLINFO_DATA_IN, - k->str, (size_t)nread, conn); - } - -#ifndef CURL_DISABLE_HTTP - if(conn->bits.chunk) { - /* - * Bless me father for I have sinned. 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. The returned 'nread' holds the number of actual - * data it wrote to the client. */ - - CHUNKcode res = - Curl_httpchunk_read(conn, k->str, nread, &nread); - - if(CHUNKE_OK < res) { - if(CHUNKE_WRITE_ERROR == res) { - failf(data, "Failed writing data"); - return CURLE_WRITE_ERROR; - } - failf(data, "Received problem %d in the chunky parser", res); - return CURLE_RECV_ERROR; - } - else if(CHUNKE_STOP == res) { - /* we're done reading chunks! */ - k->keepon &= ~KEEP_READ; /* read no more */ - - /* There are now possibly N number of bytes at the end of the - str buffer that weren't written to the client, but we don't - care about them right now. */ - } - /* If it returned OK, we just keep going */ - } -#endif /* CURL_DISABLE_HTTP */ - - if((-1 != k->maxdownload) && - (k->bytecount + nread >= k->maxdownload)) { - /* The 'excess' amount below can't be more than BUFSIZE which - always will fit in a size_t */ - size_t excess = (size_t)(k->bytecount + nread - k->maxdownload); - if (excess > 0 && !k->ignorebody) { - infof(data, - "Rewinding stream by : %d" - " bytes on url %s (size = %" FORMAT_OFF_T - ", maxdownload = %" FORMAT_OFF_T - ", bytecount = %" FORMAT_OFF_T ", nread = %d)\n", - excess, conn->data->reqdata.path, - k->size, k->maxdownload, k->bytecount, nread); - read_rewind(conn, excess); - } - - nread = (ssize_t) (k->maxdownload - k->bytecount); - if(nread < 0 ) /* this should be unusual */ - nread = 0; - - k->keepon &= ~KEEP_READ; /* we're done reading */ - } - - k->bytecount += nread; - - Curl_pgrsSetDownloadCounter(data, k->bytecount); - - if(!conn->bits.chunk && (nread || k->badheader || is_empty_data)) { - /* If this is chunky transfer, it was already written */ - - if(k->badheader && !k->ignorebody) { - /* we parsed a piece of data wrongly assuming it was a header - and now we output it as body instead */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - k->hbuflen); - if(result) - return result; - } - if(k->badheader < HEADER_ALLBAD) { - /* This switch handles various content encodings. If there's an - error here, be sure to check over the almost identical code - in http_chunks.c. - Make sure that ALL_CONTENT_ENCODINGS contains all the - encodings handled here. */ -#ifdef HAVE_LIBZ - switch (k->content_encoding) { - case IDENTITY: -#endif - /* This is the default when the server sends no - Content-Encoding header. See Curl_readwrite_init; the - memset() call initializes k->content_encoding to zero. */ - if(!k->ignorebody) - result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str, - nread); -#ifdef HAVE_LIBZ - break; - - case DEFLATE: - /* Assume CLIENTWRITE_BODY; headers are not encoded. */ - if(!k->ignorebody) - result = Curl_unencode_deflate_write(conn, k, nread); - break; - - case GZIP: - /* Assume CLIENTWRITE_BODY; headers are not encoded. */ - if(!k->ignorebody) - result = Curl_unencode_gzip_write(conn, k, nread); - break; - - case COMPRESS: - default: - failf (data, "Unrecognized content encoding type. " - "libcurl understands `identity', `deflate' and `gzip' " - "content encodings."); - result = CURLE_BAD_CONTENT_ENCODING; - break; - } -#endif - } - k->badheader = HEADER_NORMAL; /* taken care of now */ - - if(result) - return result; - } - - } /* 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_READ; - } - - } while(data_pending(conn)); - - } /* if( read from socket ) */ - - /* If we still have writing to do, we check if we have a writable - socket. */ - if((k->keepon & KEEP_WRITE) && (select_res & CSELECT_OUT)) { - /* write */ - - int i, si; - ssize_t bytes_written; - bool writedone=TRUE; - - if ((k->bytecount == 0) && (k->writebytecount == 0)) - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - - didwhat |= KEEP_WRITE; - - /* - * We loop here to do the READ and SEND loop until we run out of - * data to send or until we get EWOULDBLOCK back - */ - do { - - /* only read more data if there's no upload data already - present in the upload buffer */ - if(0 == data->reqdata.upload_present) { - /* init the "upload from here" pointer */ - data->reqdata.upload_fromhere = k->uploadbuf; - - if(!k->upload_done) { - /* HTTP pollution, this should be written nicer to become more - protocol agnostic. */ - int fillcount; - - if(k->wait100_after_headers && - (data->reqdata.proto.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->wait100_after_headers = FALSE; /* headers sent */ - k->write_after_100_header = TRUE; /* wait for the header */ - k->keepon &= ~KEEP_WRITE; /* disable writing */ - k->start100 = Curl_tvnow(); /* timeout count starts now */ - didwhat &= ~KEEP_WRITE; /* we didn't write anything actually */ - break; - } - - result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount); - if(result) - return result; - - nread = (ssize_t)fillcount; - } - else - nread = 0; /* we're done uploading/reading */ - - /* the signed int typecase of nread of for systems that has - unsigned size_t */ - if (nread<=0) { - /* done */ - k->keepon &= ~KEEP_WRITE; /* we're done writing */ - writedone = TRUE; - - if(conn->bits.rewindaftersend) { - result = Curl_readrewind(conn); - if(result) - return result; - } - break; - } - - /* store number of bytes available for upload */ - data->reqdata.upload_present = nread; - - /* convert LF to CRLF if so asked */ -#ifdef CURL_DO_LINEEND_CONV - /* always convert if we're FTPing in ASCII mode */ - if ((data->set.crlf) || (data->set.prefer_ascii)) { -#else - if (data->set.crlf) { -#endif /* CURL_DO_LINEEND_CONV */ - if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); - if(data->state.scratch == NULL) { - 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. - */ - for(i = 0, si = 0; i < nread; i++, si++) { - if (data->reqdata.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 */ - data->set.infilesize++; - } - } - else - data->state.scratch[si] = data->reqdata.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 */ - data->reqdata.upload_fromhere = data->state.scratch; - - /* set the new amount too */ - data->reqdata.upload_present = nread; - } - } - } - 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(conn, - conn->writesockfd, /* socket to send to */ - data->reqdata.upload_fromhere, /* buffer pointer */ - data->reqdata.upload_present, /* buffer size */ - &bytes_written); /* actually send away */ - if(result) - return result; - - if(data->set.verbose) - /* show the data before we change the pointer upload_fromhere */ - Curl_debug(data, CURLINFO_DATA_OUT, data->reqdata.upload_fromhere, - (size_t)bytes_written, conn); - - if(data->reqdata.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 */ - data->reqdata.upload_present -= bytes_written; - - /* advance the pointer where to find the buffer when the next send - is to happen */ - data->reqdata.upload_fromhere += bytes_written; - - writedone = TRUE; /* we are done, stop the loop */ - } - else { - /* we've uploaded that buffer now */ - data->reqdata.upload_fromhere = k->uploadbuf; - data->reqdata.upload_present = 0; /* no more bytes left */ - - if(k->upload_done) { - /* switch off writing, we're done! */ - k->keepon &= ~KEEP_WRITE; /* we're done writing */ - writedone = TRUE; - } - } - - k->writebytecount += bytes_written; - Curl_pgrsSetUploadCounter(data, k->writebytecount); - - } while(!writedone); /* loop until we're done writing! */ - - } - - } while(0); /* just to break out from! */ - - k->now = Curl_tvnow(); - if(didwhat) { - /* Update read/write counters */ - if(k->bytecountp) - *k->bytecountp = k->bytecount; /* read count */ - if(k->writebytecountp) - *k->writebytecountp = k->writebytecount; /* write count */ - } - else { - /* no read no write, this is a timeout? */ - if (k->write_after_100_header) { - /* This should allow some time for the header to arrive, but only a - very short time as otherwise it'll be too much wasted times 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. - - */ - - long ms = Curl_tvdiff(k->now, k->start100); - if(ms > CURL_TIMEOUT_EXPECT_100) { - /* we've waited long enough, continue anyway */ - k->write_after_100_header = FALSE; - k->keepon |= KEEP_WRITE; - } - } - } - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, k->now); - if (result) - return result; - - if (data->set.timeout && - ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) { - if (k->size != -1) { - failf(data, "Operation timed out after %d seconds with %" - FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received", - data->set.timeout, k->bytecount, k->size); - } else { - failf(data, "Operation timed out after %d seconds with %" - FORMAT_OFF_T " bytes received", - data->set.timeout, k->bytecount); - } - return CURLE_OPERATION_TIMEOUTED; - } - - if(!k->keepon) { - /* - * The transfer has been performed. Just make some general checks before - * returning. - */ - - if(!(conn->bits.no_body) && (k->size != -1) && - (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 */ - !data->reqdata.newurl) { - failf(data, "transfer closed with %" FORMAT_OFF_T - " bytes remaining to read", - k->size - k->bytecount); - return CURLE_PARTIAL_FILE; - } - else if(!(conn->bits.no_body) && - conn->bits.chunk && - (data->reqdata.proto.http->chunk.state != CHUNK_STOP)) { - /* - * In chunked mode, return an error if the connection is closed prior to - * the empty (terminiating) 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"); - return CURLE_PARTIAL_FILE; - } - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - } - - /* Now update the "done" boolean we return */ - *done = (bool)(0 == (k->keepon&(KEEP_READ|KEEP_WRITE))); - - return CURLE_OK; -} - - -/* - * Curl_readwrite_init() inits the readwrite session. This is inited each time for a - * transfer, sometimes multiple times on the same SessionHandle - */ - -CURLcode Curl_readwrite_init(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - - /* NB: the content encoding software depends on this initialization of - Curl_transfer_keeper.*/ - memset(k, 0, sizeof(struct Curl_transfer_keeper)); - - k->start = Curl_tvnow(); /* start time */ - k->now = k->start; /* current time is now */ - k->header = TRUE; /* assume header */ - k->httpversion = -1; /* unknown at this point */ - - k->size = data->reqdata.size; - k->maxdownload = data->reqdata.maxdownload; - k->bytecountp = data->reqdata.bytecountp; - k->writebytecountp = data->reqdata.writebytecountp; - - k->bytecount = 0; - - k->buf = data->state.buffer; - k->uploadbuf = data->state.uploadbuffer; - k->maxfd = (conn->sockfd>conn->writesockfd? - conn->sockfd:conn->writesockfd)+1; - k->hbufp = data->state.headerbuff; - k->ignorebody=FALSE; - - Curl_pgrsTime(data, TIMER_PRETRANSFER); - Curl_speedinit(data); - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - - if (!conn->bits.getheader) { - k->header = FALSE; - if(k->size > 0) - Curl_pgrsSetDownloadSize(data, k->size); - } - /* we want header and/or body, if neither then don't do this! */ - if(conn->bits.getheader || !conn->bits.no_body) { - - if(conn->sockfd != CURL_SOCKET_BAD) { - k->keepon |= KEEP_READ; - } - - if(conn->writesockfd != CURL_SOCKET_BAD) { - /* 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 && - (data->reqdata.proto.http->sending == HTTPSEND_BODY)) { - /* wait with write until we either got 100-continue or a timeout */ - k->write_after_100_header = TRUE; - k->start100 = k->start; - } - else { - if(data->state.expect100header) - /* when we've sent off the rest of the headers, we must await a - 100-continue */ - k->wait100_after_headers = TRUE; - k->keepon |= KEEP_WRITE; - } - } - } - - return CURLE_OK; -} - -/* - * 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 connectdata *conn, - curl_socket_t *sock, /* points to numsocks number - of sockets */ - int numsocks) -{ - struct SessionHandle *data = conn->data; - int bitmap = GETSOCK_BLANK; - int index = 0; - - if(numsocks < 2) - /* simple check but we might need two slots */ - return GETSOCK_BLANK; - - if(data->reqdata.keep.keepon & KEEP_READ) { - bitmap |= GETSOCK_READSOCK(index); - sock[index] = conn->sockfd; - } - - if(data->reqdata.keep.keepon & KEEP_WRITE) { - - if((conn->sockfd != conn->writesockfd) || - !(data->reqdata.keep.keepon & KEEP_READ)) { - /* only if they are not the same socket or we didn't have a readable - one, we increase index */ - if(data->reqdata.keep.keepon & KEEP_READ) - index++; /* increase index if we need two entries */ - sock[index] = conn->writesockfd; - } - - bitmap |= GETSOCK_WRITESOCK(index); - } - - return bitmap; -} - - -/* - * Transfer() - * - * This function is what performs the actual transfer. It is capable of - * doing both ways simultaneously. - * The transfer must already have been setup by a call to Curl_setup_transfer(). - * - * Note that headers are created in a preallocated buffer of a default size. - * That buffer can be enlarged on demand, but it is never shrunken again. - * - * Parts of this function was once written by the friendly Mark Butler - * . - */ - -static CURLcode -Transfer(struct connectdata *conn) -{ - CURLcode result; - struct SessionHandle *data = conn->data; - struct Curl_transfer_keeper *k = &data->reqdata.keep; - bool done=FALSE; - - if(!(conn->protocol & PROT_FILE)) - /* Only do this if we are not transferring FILE:, since the file: treatment - is different*/ - Curl_readwrite_init(conn); - - if((conn->sockfd == CURL_SOCKET_BAD) && - (conn->writesockfd == CURL_SOCKET_BAD)) - /* nothing to read, nothing to write, we're already OK! */ - return CURLE_OK; - - /* we want header and/or body, if neither then don't do this! */ - if(!conn->bits.getheader && conn->bits.no_body) - return CURLE_OK; - - while (!done) { - curl_socket_t fd_read; - curl_socket_t fd_write; - - /* limit-rate logic: if speed exceeds threshold, then do not include fd in - select set. The current speed is recalculated in each Curl_readwrite() - call */ - if ((k->keepon & KEEP_WRITE) && - (!data->set.max_send_speed || - (data->progress.ulspeed < data->set.max_send_speed) )) { - fd_write = conn->writesockfd; - k->keepon &= ~KEEP_WRITE_HOLD; - } - else { - fd_write = CURL_SOCKET_BAD; - if(k->keepon & KEEP_WRITE) - k->keepon |= KEEP_WRITE_HOLD; /* hold it */ - } - - if ((k->keepon & KEEP_READ) && - (!data->set.max_recv_speed || - (data->progress.dlspeed < data->set.max_recv_speed)) ) { - fd_read = conn->sockfd; - k->keepon &= ~KEEP_READ_HOLD; - } - else { - fd_read = CURL_SOCKET_BAD; - if(k->keepon & KEEP_READ) - k->keepon |= KEEP_READ_HOLD; /* hold it */ - } - - /* The *_HOLD logic is necessary since even though there might be no - traffic during the select interval, we still call Curl_readwrite() for - the timeout case and if we limit transfer speed we must make sure that - this function doesn't transfer anything while in HOLD status. */ - - switch (Curl_select(fd_read, fd_write, 1000)) { - case -1: /* select() error, stop reading */ -#ifdef EINTR - /* The EINTR is not serious, and it seems you might get this more - ofen when using the lib in a multi-threaded environment! */ - if(errno == EINTR) - ; - else -#endif - done = TRUE; /* no more read or write */ - continue; - case 0: /* timeout */ - default: /* readable descriptors */ - - result = Curl_readwrite(conn, &done); - break; - } - if(result) - return result; - - /* "done" signals to us if the transfer(s) are ready */ - } - - return CURLE_OK; -} - -/* - * Curl_pretransfer() is called immediately before a transfer starts. - */ -CURLcode Curl_pretransfer(struct SessionHandle *data) -{ - CURLcode res; - if(!data->change.url) { - /* we can't do anything wihout URL */ - failf(data, "No URL set!\n"); - return CURLE_URL_MALFORMAT; - } - - /* Init the SSL session ID cache here. We do it here since we want to do it - after the *_setopt() calls (that could change the size of the cache) but - before any transfer takes place. */ - res = Curl_ssl_initsessions(data, data->set.ssl.numsessions); - if(res) - return res; - - data->set.followlocation=0; /* reset the location-follow counter */ - data->state.this_is_a_follow = FALSE; /* reset this */ - data->state.errorbuf = FALSE; /* no error has occurred */ - - data->state.authproblem = FALSE; - data->state.authhost.want = data->set.httpauth; - data->state.authproxy.want = data->set.proxyauth; - - /* If there is a list of cookie files to read, do it now! */ - if(data->change.cookielist) { - Curl_cookie_loadfiles(data); - } - - /* Allow data->set.use_port to set which port to use. This needs to be - * disabled for example when we follow Location: headers to URLs using - * different ports! */ - data->state.allow_port = TRUE; - -#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) - /************************************************************* - * Tell signal handler to ignore SIGPIPE - *************************************************************/ - if(!data->set.no_signal) - data->state.prev_signal = signal(SIGPIPE, SIG_IGN); -#endif - - Curl_initinfo(data); /* reset session-specific information "variables" */ - Curl_pgrsStartNow(data); - - return CURLE_OK; -} - -/* - * Curl_posttransfer() is called immediately after a transfer ends - */ -CURLcode Curl_posttransfer(struct SessionHandle *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->progress.flags & PGRS_HIDE) && - !data->progress.callback) - /* only output if we don't use a progress callback and we're not hidden */ - fprintf(data->set.err, "\n"); - - return CURLE_OK; -} - -/* - * strlen_url() returns the length of the given URL if the spaces within the - * URL were properly URL encoded. - */ -static int strlen_url(char *url) -{ - char *ptr; - int newlen=0; - bool left=TRUE; /* left side of the ? */ - - for(ptr=url; *ptr; ptr++) { - switch(*ptr) { - case '?': - left=FALSE; - default: - newlen++; - break; - case ' ': - if(left) - newlen+=3; - else - newlen++; - break; - } - } - return newlen; -} - -/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in - * the source URL accordingly. - */ -static void strcpy_url(char *output, char *url) -{ - /* we must add this with whitespace-replacing */ - bool left=TRUE; - char *iptr; - char *optr = output; - for(iptr = url; /* read from here */ - *iptr; /* until zero byte */ - iptr++) { - switch(*iptr) { - case '?': - left=FALSE; - default: - *optr++=*iptr; - break; - case ' ': - if(left) { - *optr++='%'; /* add a '%' */ - *optr++='2'; /* add a '2' */ - *optr++='0'; /* add a '0' */ - } - else - *optr++='+'; /* add a '+' here */ - break; - } - } - *optr=0; /* zero terminate output buffer */ - -} - -/* - * 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. - */ -CURLcode Curl_follow(struct SessionHandle *data, - char *newurl, /* this 'newurl' is the Location: string, - and it must be malloc()ed before passed - here */ - bool retry) /* set TRUE if this is a request retry as - opposed to a real redirect following */ -{ - /* Location: redirect */ - char prot[16]; /* URL protocol string storage */ - char letter; /* used for a silly sscanf */ - size_t newlen; - char *newest; - - if(!retry) { - if ((data->set.maxredirs != -1) && - (data->set.followlocation >= data->set.maxredirs)) { - failf(data,"Maximum (%d) redirects followed", data->set.maxredirs); - return CURLE_TOO_MANY_REDIRECTS; - } - - /* mark the next request as a followed location: */ - data->state.this_is_a_follow = TRUE; - - data->set.followlocation++; /* count location-followers */ - } - - if(data->set.http_auto_referer) { - /* We are asked to automatically set the previous URL as the - referer when we get the next URL. We pick the ->url field, - which may or may not be 100% correct */ - - if(data->change.referer_alloc) - /* If we already have an allocated referer, free this first */ - free(data->change.referer); - - data->change.referer = strdup(data->change.url); - data->change.referer_alloc = TRUE; /* yes, free this later */ - } - - if(2 != sscanf(newurl, "%15[^?&/:]://%c", prot, &letter)) { - /*** - *DANG* this is an RFC 2068 violation. The URL is supposed - to be absolute and this doesn't seem to be that! - *** - Instead, we have to TRY to append this new path to the old URL - to the right of the host part. Oh crap, this is doomed to cause - problems in the future... - */ - char *protsep; - char *pathsep; - - char *useurl = newurl; - size_t urllen; - - /* we must make our own copy of the URL to play with, as it may - point to read-only data */ - char *url_clone=strdup(data->change.url); - - if(!url_clone) - return CURLE_OUT_OF_MEMORY; /* skip out of this NOW */ - - /* protsep points to the start of the host name */ - protsep=strstr(url_clone, "//"); - if(!protsep) - protsep=url_clone; - else - protsep+=2; /* pass the slashes */ - - if('/' != newurl[0]) { - int level=0; - - /* 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's one available */ - pathsep = strrchr(protsep, '/'); - if(pathsep) - *pathsep=0; - - /* 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 */ - - if((useurl[0] == '.') && (useurl[1] == '/')) - useurl+=2; /* just skip 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; - } - } - } - } - else { - /* We got a new absolute path for this server, cut off from the - first slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) { - /* When people use badly formatted URLs, such as - "http://www.url.com?dir=/home/daniel" we must not use the first - slash, if there's a ?-letter before it! */ - char *sep = strchr(protsep, '?'); - if(sep && (sep < pathsep)) - pathsep = sep; - *pathsep=0; - } - else { - /* There was no slash. Now, since we might be operating on a badly - formatted URL, such as "http://www.url.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) - *pathsep=0; - } - } - - /* If the new part contains a space, this is a mighty stupid redirect - but we still make an effort to do "right". To the left of a '?' - letter we replace each space with %20 while it is replaced with '+' - on the right side of the '?' letter. - */ - newlen = strlen_url(useurl); - - urllen = strlen(url_clone); - - newest=(char *)malloc( urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); - - if(!newest) { - free(url_clone); /* don't leak this */ - return CURLE_OUT_OF_MEMORY; /* go out from this */ - } - - /* copy over the root url part */ - memcpy(newest, url_clone, urllen); - - /* check if we need to append a slash */ - if(('/' == useurl[0]) || (protsep && !*protsep)) - ; - else - newest[urllen++]='/'; - - /* then append the new piece on the right side */ - strcpy_url(&newest[urllen], useurl); - - free(newurl); /* newurl is the allocated pointer */ - free(url_clone); - newurl = newest; - } - else { - /* This is an absolute URL, don't allow the custom port number */ - data->state.allow_port = FALSE; - - if(strchr(newurl, ' ')) { - /* This new URL contains at least one space, this is a mighty stupid - redirect but we still make an effort to do "right". */ - newlen = strlen_url(newurl); - - newest = malloc(newlen+1); /* get memory for this */ - if(newest) { - strcpy_url(newest, newurl); /* create a space-free URL */ - - free(newurl); /* that was no good */ - newurl = newest; /* use this instead now */ - } - } - - } - - if(data->change.url_alloc) - free(data->change.url); - else - data->change.url_alloc = TRUE; /* the URL is allocated */ - - data->change.url = newurl; - newurl = NULL; /* don't free! */ - - infof(data, "Issue another request to this URL: '%s'\n", data->change.url); - - /* - * We get here when the HTTP code is 300-399 (and 401). We need to perform - * differently based on exactly what return code there was. - * - * News from 7.10.6: we can also get here on a 401 or 407, in case we act on - * a HTTP (proxy-) authentication scheme other than Basic. - */ - switch(data->info.httpcode) { - /* 401 - Act on a www-authentication, we keep on moving and do the - Authorization: XXXX header in the HTTP request code snippet */ - /* 407 - Act on a proxy-authentication, we keep on moving and do the - Proxy-Authorization: XXXX header in the HTTP request code snippet */ - /* 300 - Multiple Choices */ - /* 306 - Not used */ - /* 307 - Temporary Redirect */ - default: /* for all above (and the unknown ones) */ - /* 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 RFC2616, section 10.3.2): - * - * Note: When automatically redirecting a POST request after receiving a - * 301 status code, some existing HTTP/1.0 user agents will erroneously - * change it into a GET request. - * - * ---- - * - * Warning: Because most of importants user agents do this obvious RFC2616 - * violation, many webservers expect this misbehavior. So these servers - * often answers to a POST request with an error page. To be sure that - * libcurl gets the page that most user agents would get, libcurl has to - * force GET: - */ - if( data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM) { - infof(data, - "Violate RFC 2616/10.3.2 and switch from POST to GET\n"); - data->set.httpreq = HTTPREQ_GET; - } - break; - case 302: /* Found */ - /* (From 10.3.3) - - Note: RFC 1945 and RFC 2068 specify that the client is not allowed - to change the method on the redirected request. However, most - existing user agent implementations treat 302 as if it were a 303 - response, performing a GET on the Location field-value regardless - of the original request method. The status codes 303 and 307 have - been added for servers that wish to make unambiguously clear which - kind of reaction is expected of the client. - - (From 10.3.4) - - Note: Many pre-HTTP/1.1 user agents do not understand the 303 - status. When interoperability with such clients is a concern, the - 302 status code may be used instead, since most user agents react - to a 302 response as described here for 303. - */ - case 303: /* See Other */ - /* Disable both types of POSTs, since doing a second POST when - * following isn't what anyone would want! */ - if(data->set.httpreq != HTTPREQ_GET) { - data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ - infof(data, "Disables POST, goes with %s\n", - data->set.opt_no_body?"HEAD":"GET"); - } - break; - case 304: /* Not Modified */ - /* 304 means we did a conditional request and it was "Not modified". - * 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 - * via the proxy. 305 responses MUST only be generated by origin - * servers." - */ - break; - } - Curl_pgrsTime(data, TIMER_REDIRECT); - Curl_pgrsResetTimes(data); - - return CURLE_OK; -} - -static CURLcode -Curl_connect_host(struct SessionHandle *data, - struct connectdata **conn) -{ - CURLcode res = CURLE_OK; - int urlchanged = FALSE; - - do { - bool async; - bool protocol_done=TRUE; /* will be TRUE always since this is only used - within the easy interface */ - Curl_pgrsTime(data, TIMER_STARTSINGLE); - data->change.url_changed = FALSE; - res = Curl_connect(data, conn, &async, &protocol_done); - - if((CURLE_OK == res) && async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - res = Curl_wait_for_resolv(*conn, NULL); - if(CURLE_OK == res) - /* Resolved, continue with the connection */ - res = Curl_async_resolved(*conn, &protocol_done); - else - /* if we can't resolve, we kill this "connection" now */ - (void)Curl_disconnect(*conn); - } - if(res) - break; - - /* If a callback (or something) has altered the URL we should use within - the Curl_connect(), we detect it here and act as if we are redirected - to the new URL */ - urlchanged = data->change.url_changed; - if ((CURLE_OK == res) && urlchanged) { - res = Curl_done(conn, res, FALSE); - if(CURLE_OK == res) { - char *gotourl = strdup(data->change.url); - res = Curl_follow(data, gotourl, FALSE); - if(res) - free(gotourl); - } - } - } while (urlchanged && res == CURLE_OK); - - return res; -} - -/* Returns TRUE and sets '*url' if a request retry is wanted */ -bool Curl_retry_request(struct connectdata *conn, - char **url) -{ - bool retry = FALSE; - struct SessionHandle *data = conn->data; - - if((data->reqdata.keep.bytecount+conn->headerbytecount == 0) && - conn->bits.reuse && - !conn->bits.no_body) { - /* We got no data, we attempted to re-use a connection and yet we want a - "body". This might happen if the connection was left alive when we were - done using it before, but that was closed when we wanted to read from - it again. Bad luck. Retry the same request on a fresh connect! */ - infof(conn->data, "Connection died, retrying a fresh connect\n"); - *url = strdup(conn->data->change.url); - - conn->bits.close = TRUE; /* close this connection */ - 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 - transfered! */ - retry = TRUE; - } - - return retry; -} - -/* - * Curl_perform() is the internal high-level function that gets called by the - * external curl_easy_perform() function. It inits, performs and cleans up a - * single file transfer. - */ -CURLcode Curl_perform(struct SessionHandle *data) -{ - CURLcode res; - CURLcode res2; - struct connectdata *conn=NULL; - char *newurl = NULL; /* possibly a new URL to follow to! */ - bool retry = FALSE; - - data->state.used_interface = Curl_if_easy; - - res = Curl_pretransfer(data); - if(res) - return res; - - /* - * It is important that there is NO 'return' from this function at any other - * place than falling down to the end of the function! This is because we - * have cleanup stuff that must be done before we get back, and that is only - * performed after this do-while loop. - */ - - do { - res = Curl_connect_host(data, &conn); /* primary connection */ - - if(res == CURLE_OK) { - bool do_done; - if(data->set.connect_only) { - /* keep connection open for application to use the socket */ - conn->bits.close = FALSE; - res = Curl_done(&conn, CURLE_OK, FALSE); - break; - } - res = Curl_do(&conn, &do_done); - - if(res == CURLE_OK) { - res = Transfer(conn); /* now fetch that URL please */ - if(res == CURLE_OK) { - retry = Curl_retry_request(conn, &newurl); - - if(!retry) - /* - * We must duplicate the new URL here as the connection data may - * be free()ed in the Curl_done() function. - */ - newurl = data->reqdata.newurl?strdup(data->reqdata.newurl):NULL; - } - else { - /* The transfer phase returned error, we mark the connection to get - * closed to prevent being re-used. This is becasue we can't - * possibly know if the connection is in a good shape or not now. */ - conn->bits.close = TRUE; - - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - /* if we failed anywhere, we must clean up the secondary socket if - it was used */ - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } - } - - /* Always run Curl_done(), even if some of the previous calls - failed, but return the previous (original) error code */ - res2 = Curl_done(&conn, res, FALSE); - - if(CURLE_OK == res) - res = res2; - } - else - /* Curl_do() failed, clean up left-overs in the done-call */ - res2 = Curl_done(&conn, res, FALSE); - - /* - * Important: 'conn' cannot be used here, since it may have been closed - * in 'Curl_done' or other functions. - */ - - if((res == CURLE_OK) && newurl) { - res = Curl_follow(data, newurl, retry); - if(CURLE_OK == res) { - newurl = NULL; - continue; - } - } - } - break; /* it only reaches here when this shouldn't loop */ - - } while(1); /* loop if Location: */ - - if(newurl) - free(newurl); - - if(res && !data->state.errorbuf) { - /* - * As an extra precaution: if no error string has been set and there was - * an error, use the strerror() string or if things are so bad that not - * even that is good, set a bad string that mentions the error code. - */ - const char *str = curl_easy_strerror(res); - if(!str) - failf(data, "unspecified error %d", (int)res); - else - failf(data, "%s", str); - } - - /* run post-transfer uncondionally, but don't clobber the return code if - we already have an error code recorder */ - res2 = Curl_posttransfer(data); - if(!res && res2) - res = res2; - - return res; -} - -/* - * Curl_setup_transfer() is called to setup some basic properties for the - * upcoming transfer. - */ -CURLcode -Curl_setup_transfer( - struct connectdata *c_conn, /* connection 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 */ - curl_off_t *bytecountp, /* return number of bytes read or NULL */ - int writesockindex, /* socket index to write to, it may very - well be the same we read from. -1 - disables */ - curl_off_t *writecountp /* return number of bytes written or - NULL */ - ) -{ - struct connectdata *conn = (struct connectdata *)c_conn; - struct SessionHandle *data = conn->data; - - if(!conn) - return CURLE_BAD_FUNCTION_ARGUMENT; - - curlassert((sockindex <= 1) && (sockindex >= -1)); - - /* now copy all input parameters */ - conn->sockfd = sockindex == -1 ? - CURL_SOCKET_BAD : conn->sock[sockindex]; - conn->writesockfd = writesockindex == -1 ? - CURL_SOCKET_BAD:conn->sock[writesockindex]; - conn->bits.getheader = getheader; - - data->reqdata.size = size; - data->reqdata.bytecountp = bytecountp; - data->reqdata.writebytecountp = writecountp; - - return CURLE_OK; -} diff --git a/Utilities/cmcurl/transfer.h b/Utilities/cmcurl/transfer.h deleted file mode 100644 index 3c415cc..0000000 --- a/Utilities/cmcurl/transfer.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __TRANSFER_H -#define __TRANSFER_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ -CURLcode Curl_perform(struct SessionHandle *data); -CURLcode Curl_pretransfer(struct SessionHandle *data); -CURLcode Curl_second_connect(struct connectdata *conn); -CURLcode Curl_posttransfer(struct SessionHandle *data); -CURLcode Curl_follow(struct SessionHandle *data, char *newurl, bool retry); -CURLcode Curl_readwrite(struct connectdata *conn, bool *done); -int Curl_single_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -CURLcode Curl_readwrite_init(struct connectdata *conn); -CURLcode Curl_readrewind(struct connectdata *conn); -CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); -bool Curl_retry_request(struct connectdata *conn, char **url); - -/* This sets up a forthcoming transfer */ -CURLcode -Curl_setup_transfer (struct connectdata *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 */ - curl_off_t *bytecountp, /* return number of bytes read */ - int writesockindex, /* socket index to write to, it may - very well be the same we read from. - -1 disables */ - curl_off_t *writecountp /* return number of bytes written */ -); -#endif diff --git a/Utilities/cmcurl/url.c b/Utilities/cmcurl/url.c deleted file mode 100644 index da12231..0000000 --- a/Utilities/cmcurl/url.c +++ /dev/null @@ -1,4252 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* -- WIN32 approved -- */ - -#include "setup.h" - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#include - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef VMS -#include -#include -#endif - -#ifdef HAVE_SETJMP_H -#include -#endif - -#ifndef HAVE_SOCKET -#error "We can't compile without socket() support!" -#endif -#endif - -#ifdef USE_LIBIDN -#include -#include -#include -#ifdef HAVE_IDN_FREE_H -#include -#else -void idn_free (void *ptr); /* prototype from idn-free.h, not provided by - libidn 0.4.5's make install! */ -#endif -#ifndef HAVE_IDN_FREE -/* if idn_free() was not found in this version of libidn, use plain free() - instead */ -#define idn_free(x) (free)(x) -#endif -#endif /* USE_LIBIDN */ - -#include "urldata.h" -#include "netrc.h" - -#include "formdata.h" -#include "base64.h" -#include "sslgen.h" -#include "hostip.h" -#include "transfer.h" -#include "sendf.h" -#include "progress.h" -#include "cookie.h" -#include "strequal.h" -#include "strerror.h" -#include "escape.h" -#include "strtok.h" -#include "share.h" -#include "content_encoding.h" -#include "http_digest.h" -#include "http_negotiate.h" -#include "select.h" -#include "multiif.h" -#include "easyif.h" - -/* And now for the protocols */ -#include "ftp.h" -#include "dict.h" -#include "telnet.h" -#include "tftp.h" -#include "http.h" -#include "file.h" -#include "ldap.h" -#include "ssh.h" -#include "url.h" -#include "connect.h" -#include "inet_ntop.h" -#include "http_ntlm.h" -#include "socks.h" -#include - -#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) -#include "inet_ntoa_r.h" -#endif - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#ifdef HAVE_KRB4 -#include "krb4.h" -#endif -#include "memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* Local static prototypes */ -static long ConnectionKillOne(struct SessionHandle *data); -static bool ConnectionExists(struct SessionHandle *data, - struct connectdata *needle, - struct connectdata **usethis); -static long ConnectionStore(struct SessionHandle *data, - struct connectdata *conn); -static bool IsPipeliningPossible(struct SessionHandle *handle); -static bool IsPipeliningEnabled(struct SessionHandle *handle); -static void conn_free(struct connectdata *conn); - -static void signalPipeClose(struct curl_llist *pipe); - -#define MAX_PIPELINE_LENGTH 5 - -/* - * We use this ZERO_NULL to avoid picky compiler warnings, - * when assigning a NULL pointer to a function pointer var. - */ - -#define ZERO_NULL 0 - -#ifndef USE_ARES -/* not for ares builds */ - -#ifndef WIN32 -/* not for WIN32 builds */ - -#ifdef HAVE_SIGSETJMP -extern sigjmp_buf curl_jmpenv; -#endif - -#ifdef SIGALRM -static -RETSIGTYPE alarmfunc(int sig) -{ - /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ - (void)sig; -#ifdef HAVE_SIGSETJMP - siglongjmp(curl_jmpenv, 1); -#endif - /*return;*/ /* not reahed, and has no effect anyway */ -} -#endif /* SIGALRM */ -#endif /* WIN32 */ -#endif /* USE_ARES */ - -void Curl_safefree(void *ptr) -{ - if(ptr) - free(ptr); -} - -static void close_connections(struct SessionHandle *data) -{ - /* Loop through all open connections and kill them one by one */ - while(-1 != ConnectionKillOne(data)) - ; /* empty loop */ -} - -/* - * This is the internal function curl_easy_cleanup() calls. This should - * cleanup and free all resources associated with this sessionhandle. - * - * NOTE: if we ever add something that attempts to write to a socket or - * similar here, we must ignore SIGPIPE first. It is currently only done - * when curl_easy_perform() is invoked. - */ - -CURLcode Curl_close(struct SessionHandle *data) -{ - struct Curl_multi *m = data->multi; - -#ifdef CURLDEBUG - /* only for debugging, scan through all connections and see if there's a - pipe reference still identifying this handle */ - - if(data->state.is_in_pipeline) - fprintf(stderr, "CLOSED when in pipeline!\n"); - - if(data->state.connc && data->state.connc->type == CONNCACHE_MULTI) { - struct conncache *c = data->state.connc; - int i; - struct curl_llist *pipe; - struct curl_llist_element *curr; - struct connectdata *connptr; - - for(i=0; i< c->num; i++) { - connptr = c->connects[i]; - if(!connptr) - continue; - - pipe = connptr->send_pipe; - if(pipe) { - for (curr = pipe->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "MAJOR problem we %p are still in send pipe for %p done %d\n", - data, connptr, connptr->bits.done); - } - } - } - pipe = connptr->recv_pipe; - if(pipe) { - for (curr = pipe->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "MAJOR problem we %p are still in recv pipe for %p done %d\n", - data, connptr, connptr->bits.done); - } - } - } - } - } -#endif - - if(m) - /* This handle is still part of a multi handle, take care of this first - and detach this handle from there. */ - Curl_multi_rmeasy(data->multi, data); - - data->magic = 0; /* force a clear AFTER the possibly enforced removal from - the multi handle, since that function uses the magic - field! */ - - if(data->state.connc) { - - if(data->state.connc->type == CONNCACHE_PRIVATE) { - /* close all connections still alive that are in the private connection - cache, as we no longer have the pointer left to the shared one. */ - close_connections(data); - - /* free the connection cache if allocated privately */ - Curl_rm_connc(data->state.connc); - } - } - - if(data->state.shared_conn) { - /* marked to be used by a pending connection so we can't kill this handle - just yet */ - data->state.closed = TRUE; - return CURLE_OK; - } - - if ( ! (data->share && data->share->hostcache) ) { - if ( !Curl_global_host_cache_use(data)) { - Curl_hash_destroy(data->dns.hostcache); - } - } - - /* Free the pathbuffer */ - Curl_safefree(data->reqdata.pathbuffer); - Curl_safefree(data->reqdata.proto.generic); - - /* Close down all open SSL info and sessions */ - Curl_ssl_close_all(data); - Curl_safefree(data->state.first_host); - Curl_safefree(data->state.scratch); - - if(data->change.referer_alloc) - free(data->change.referer); - - if(data->change.url_alloc) - free(data->change.url); - - Curl_safefree(data->state.headerbuff); - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - if(data->set.cookiejar) { - if(data->change.cookielist) { - /* If there is a list of cookie files to read, do it first so that - we have all the told files read before we write the new jar */ - Curl_cookie_loadfiles(data); - } - - /* we have a "destination" for all the cookies to get dumped to */ - if(Curl_cookie_output(data->cookies, data->set.cookiejar)) - infof(data, "WARNING: failed to save cookies in %s\n", - data->set.cookiejar); - } - else { - if(data->change.cookielist) - /* since nothing is written, we can just free the list of cookie file - names */ - curl_slist_free_all(data->change.cookielist); /* clean up list */ - } - - if( !data->share || (data->cookies != data->share->cookies) ) { - Curl_cookie_cleanup(data->cookies); - } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); -#endif - - Curl_digest_cleanup(data); - - Curl_safefree(data->info.contenttype); - - /* this destroys the channel and we cannot use it anymore after this */ - ares_destroy(data->state.areschannel); - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - /* close iconv conversion descriptors */ - if (data->inbound_cd != (iconv_t)-1) { - iconv_close(data->inbound_cd); - } - if (data->outbound_cd != (iconv_t)-1) { - iconv_close(data->outbound_cd); - } - if (data->utf8_cd != (iconv_t)-1) { - iconv_close(data->utf8_cd); - } -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - - /* No longer a dirty share, if it exists */ - if (data->share) - data->share->dirty--; - - free(data); - return CURLE_OK; -} - -/* create a connection cache of a private or multi type */ -struct conncache *Curl_mk_connc(int type, - int amount) /* set -1 to use default */ -{ - /* It is subject for debate how many default connections to have for a multi - connection cache... */ - int default_amount = amount == -1? - ((type == CONNCACHE_PRIVATE)?5:10):amount; - struct conncache *c; - - c= calloc(sizeof(struct conncache), 1); - if(!c) - return NULL; - - c->connects = calloc(sizeof(struct connectdata *), default_amount); - if(!c->connects) { - free(c); - return NULL; - } - - c->num = default_amount; - - return c; -} - -/* Change number of entries of a connection cache */ -CURLcode Curl_ch_connc(struct SessionHandle *data, - struct conncache *c, - long newamount) -{ - long i; - struct connectdata **newptr; - - if(newamount < 1) - newamount = 1; /* we better have at least one entry */ - - if(!c) { - /* we get a NULL pointer passed in as connection cache, which means that - there is no cache created for this SessionHandle just yet, we create a - brand new with the requested size. - */ - data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, newamount); - if(!data->state.connc) - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; - } - - if(newamount < c->num) { - /* Since this number is *decreased* from the existing number, we must - close the possibly open connections that live on the indexes that - are being removed! - - NOTE: for conncache_multi cases we must make sure that we only - close handles not in use. - */ - for(i=newamount; i< c->num; i++) - Curl_disconnect(c->connects[i]); - - /* If the most recent connection is no longer valid, mark it - invalid. */ - if(data->state.lastconnect <= newamount) - data->state.lastconnect = -1; - } - if(newamount > 0) { - newptr= (struct connectdata **) - realloc(c->connects, sizeof(struct connectdata *) * newamount); - if(!newptr) - /* we closed a few connections in vain, but so what? */ - return CURLE_OUT_OF_MEMORY; - - /* nullify the newly added pointers */ - for(i=c->num; iconnects = newptr; - c->num = newamount; - } - /* we no longer support less than 1 as size for the connection cache, and - I'm not sure it ever worked to set it to zero */ - return CURLE_OK; -} - -/* Free a connection cache. This is called from Curl_close() and - curl_multi_cleanup(). */ -void Curl_rm_connc(struct conncache *c) -{ - if(c->connects) { - int i; - for(i = 0; i < c->num; ++i) - conn_free(c->connects[i]); - - free(c->connects); - } - - free(c); -} - -/** - * Curl_open() - * - * @param curl is a pointer to a sessionhandle pointer that gets set by this - * function. - * @return CURLcode - */ - -CURLcode Curl_open(struct SessionHandle **curl) -{ - CURLcode res = CURLE_OK; - struct SessionHandle *data; - - /* Very simple start-up: alloc the struct, init it with zeroes and return */ - data = (struct SessionHandle *)calloc(1, sizeof(struct SessionHandle)); - if(!data) - /* this is a very serious error */ - return CURLE_OUT_OF_MEMORY; - - data->magic = CURLEASY_MAGIC_NUMBER; - -#ifdef USE_ARES - if(ARES_SUCCESS != ares_init(&data->state.areschannel)) { - free(data); - return CURLE_FAILED_INIT; - } - /* make sure that all other returns from this function should destroy the - ares channel before returning error! */ -#endif - - /* We do some initial setup here, all those fields that can't be just 0 */ - - data->state.headerbuff=(char*)malloc(HEADERSIZE); - if(!data->state.headerbuff) - res = CURLE_OUT_OF_MEMORY; - else { - data->state.headersize=HEADERSIZE; - - data->set.out = stdout; /* default output to stdout */ - data->set.in = stdin; /* default input from stdin */ - data->set.err = stderr; /* default stderr to stderr */ - - /* use fwrite as default function to store output */ - data->set.fwrite = (curl_write_callback)fwrite; - - /* use fread as default function to read input */ - data->set.fread = (curl_read_callback)fread; - - /* conversion callbacks for non-ASCII hosts */ - data->set.convfromnetwork = (curl_conv_callback)ZERO_NULL; - data->set.convtonetwork = (curl_conv_callback)ZERO_NULL; - data->set.convfromutf8 = (curl_conv_callback)ZERO_NULL; - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - /* conversion descriptors for iconv calls */ - data->outbound_cd = (iconv_t)-1; - data->inbound_cd = (iconv_t)-1; - data->utf8_cd = (iconv_t)-1; -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - - data->set.infilesize = -1; /* we don't know any size */ - data->set.postfieldsize = -1; - data->set.maxredirs = -1; /* allow any amount by default */ - data->state.current_speed = -1; /* init to negative == impossible */ - - data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */ - data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ - data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ - data->set.ftp_filemethod = FTPFILE_MULTICWD; - data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ - - /* make libcurl quiet by default: */ - data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ - data->progress.flags |= PGRS_HIDE; - - /* Set the default size of the SSL session ID cache */ - data->set.ssl.numsessions = 5; - - data->set.proxyport = 1080; - data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ - data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */ - data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */ - - /* This no longer creates a connection cache here. It is instead made on - the first call to curl_easy_perform() or when the handle is added to a - multi stack. */ - - data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth - type */ - - /* most recent connection is not yet defined */ - data->state.lastconnect = -1; - - Curl_easy_initHandleData(data); - - /* - * libcurl 7.10 introduced SSL verification *by default*! This needs to be - * switched off unless wanted. - */ - data->set.ssl.verifypeer = TRUE; - data->set.ssl.verifyhost = 2; - data->set.ssl.sessionid = TRUE; /* session ID caching enabled by default */ -#ifdef CURL_CA_BUNDLE - /* This is our preferred CA cert bundle since install time */ - data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; -#endif - } - - if(res) { - ares_destroy(data->state.areschannel); - if(data->state.headerbuff) - free(data->state.headerbuff); - free(data); - data = NULL; - } - else - *curl = data; - - return res; -} - -CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, - va_list param) -{ - char *argptr; - CURLcode result = CURLE_OK; - - switch(option) { - case CURLOPT_DNS_CACHE_TIMEOUT: - data->set.dns_cache_timeout = va_arg(param, int); - break; - case CURLOPT_DNS_USE_GLOBAL_CACHE: - { - int use_cache = va_arg(param, int); - if (use_cache) { - Curl_global_host_cache_init(); - } - - data->set.global_dns_cache = (bool)(0 != use_cache); - } - break; - case CURLOPT_SSL_CIPHER_LIST: - /* set a list of cipher we want to use in the SSL connection */ - data->set.ssl.cipher_list = va_arg(param, char *); - break; - - case CURLOPT_RANDOM_FILE: - /* - * This is the path name to a file that contains random data to seed - * the random SSL stuff with. The file is only used for reading. - */ - data->set.ssl.random_file = va_arg(param, char *); - break; - case CURLOPT_EGDSOCKET: - /* - * The Entropy Gathering Daemon socket pathname - */ - data->set.ssl.egdsocket = va_arg(param, char *); - break; - case CURLOPT_MAXCONNECTS: - /* - * Set the absolute number of maximum simultaneous alive connection that - * libcurl is allowed to have. - */ - result = Curl_ch_connc(data, data->state.connc, va_arg(param, long)); - break; - case CURLOPT_FORBID_REUSE: - /* - * When this transfer is done, it must not be left to be reused by a - * subsequent transfer but shall be closed immediately. - */ - data->set.reuse_forbid = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_FRESH_CONNECT: - /* - * This transfer shall not use a previously cached connection but - * should be made with a fresh new connect! - */ - data->set.reuse_fresh = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_VERBOSE: - /* - * Verbose means infof() calls that give a lot of information about - * the connection and transfer procedures as well as internal choices. - */ - data->set.verbose = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_HEADER: - /* - * Set to include the header in the general data output stream. - */ - data->set.include_header = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_NOPROGRESS: - /* - * Shut off the internal supported progress meter - */ - data->set.hide_progress = (bool)(0 != va_arg(param, long)); - if(data->set.hide_progress) - data->progress.flags |= PGRS_HIDE; - else - data->progress.flags &= ~PGRS_HIDE; - break; - case CURLOPT_NOBODY: - /* - * Do not include the body part in the output data stream. - */ - data->set.opt_no_body = (bool)(0 != va_arg(param, long)); - if(data->set.opt_no_body) - /* in HTTP lingo, this means using the HEAD request */ - data->set.httpreq = HTTPREQ_HEAD; - break; - case CURLOPT_FAILONERROR: - /* - * Don't output the >=300 error code HTML-page, but instead only - * return error. - */ - data->set.http_fail_on_error = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_UPLOAD: - case CURLOPT_PUT: - /* - * We want to sent data to the remote host. If this is HTTP, that equals - * using the PUT request. - */ - data->set.upload = (bool)(0 != va_arg(param, long)); - if(data->set.upload) - /* If this is HTTP, PUT is what's needed to "upload" */ - data->set.httpreq = HTTPREQ_PUT; - break; - case CURLOPT_FILETIME: - /* - * Try to get the file time of the remote document. The time will - * later (possibly) become available using curl_easy_getinfo(). - */ - data->set.get_filetime = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_FTP_CREATE_MISSING_DIRS: - /* - * An FTP option that modifies an upload to create missing directories on - * the server. - */ - data->set.ftp_create_missing_dirs = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_FTP_RESPONSE_TIMEOUT: - /* - * An FTP option that specifies how quickly an FTP response must be - * obtained before it is considered failure. - */ - data->set.ftp_response_timeout = va_arg( param , long ); - break; - case CURLOPT_FTPLISTONLY: - /* - * An FTP option that changes the command to one that asks for a list - * only, no file info details. - */ - data->set.ftp_list_only = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_FTPAPPEND: - /* - * We want to upload and append to an existing (FTP) file. - */ - data->set.ftp_append = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_FTP_FILEMETHOD: - /* - * How do access files over FTP. - */ - data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long); - break; - case CURLOPT_NETRC: - /* - * Parse the $HOME/.netrc file - */ - data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long); - break; - case CURLOPT_NETRC_FILE: - /* - * Use this file instead of the $HOME/.netrc file - */ - data->set.netrc_file = va_arg(param, char *); - break; - case CURLOPT_TRANSFERTEXT: - /* - * This option was previously named 'FTPASCII'. Renamed to work with - * more protocols than merely FTP. - * - * Transfer using ASCII (instead of BINARY). - */ - data->set.prefer_ascii = (bool)(0 != va_arg(param, long)); - break; - case CURLOPT_TIMECONDITION: - /* - * Set HTTP time condition. This must be one of the defines in the - * curl/curl.h header file. - */ - data->set.timecondition = (curl_TimeCond)va_arg(param, long); - break; - case CURLOPT_TIMEVALUE: - /* - * This is the value to compare with the remote document with the - * method set with CURLOPT_TIMECONDITION - */ - data->set.timevalue = (time_t)va_arg(param, long); - break; - case CURLOPT_SSLVERSION: - /* - * Set explicit SSL version to try to connect with, as some SSL - * implementations are lame. - */ - data->set.ssl.version = va_arg(param, long); - break; - -#ifndef CURL_DISABLE_HTTP - case CURLOPT_AUTOREFERER: - /* - * Switch on automatic referer that gets set if curl follows locations. - */ - data->set.http_auto_referer = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_ENCODING: - /* - * String to use at the value of Accept-Encoding header. - * - * 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 don't send an Accept-Encoding header - * and ignore an received Content-Encoding header. - * - */ - data->set.encoding = va_arg(param, char *); - if(data->set.encoding && !*data->set.encoding) - data->set.encoding = (char*)ALL_CONTENT_ENCODINGS; - break; - - case CURLOPT_FOLLOWLOCATION: - /* - * Follow Location: header hints on a HTTP-server. - */ - data->set.http_follow_location = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_UNRESTRICTED_AUTH: - /* - * Send authentication (user+password) when following locations, even when - * hostname changed. - */ - data->set.http_disable_hostname_check_before_authentication = - (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_MAXREDIRS: - /* - * The maximum amount of hops you allow curl to follow Location: - * headers. This should mostly be used to detect never-ending loops. - */ - data->set.maxredirs = va_arg(param, long); - break; - - case CURLOPT_POST: - /* Does this option serve a purpose anymore? Yes it does, when - CURLOPT_POSTFIELDS isn't used and the POST data is read off the - callback! */ - if(va_arg(param, long)) { - data->set.httpreq = HTTPREQ_POST; - data->set.opt_no_body = FALSE; /* this is implied */ - } - else - data->set.httpreq = HTTPREQ_GET; - break; - - case CURLOPT_POSTFIELDS: - /* - * A string with POST data. Makes curl HTTP POST. Even if it is NULL. - */ - data->set.postfields = va_arg(param, char *); - data->set.httpreq = HTTPREQ_POST; - break; - - case CURLOPT_POSTFIELDSIZE: - /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. - */ - data->set.postfieldsize = va_arg(param, long); - break; - - case CURLOPT_POSTFIELDSIZE_LARGE: - /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. - */ - data->set.postfieldsize = va_arg(param, curl_off_t); - break; - - case CURLOPT_HTTPPOST: - /* - * Set to make us do HTTP POST - */ - data->set.httppost = va_arg(param, struct curl_httppost *); - data->set.httpreq = HTTPREQ_POST_FORM; - data->set.opt_no_body = FALSE; /* this is implied */ - break; - - case CURLOPT_REFERER: - /* - * String to set in the HTTP Referer: field. - */ - if(data->change.referer_alloc) { - free(data->change.referer); - data->change.referer_alloc = FALSE; - } - data->set.set_referer = va_arg(param, char *); - data->change.referer = data->set.set_referer; - break; - - case CURLOPT_USERAGENT: - /* - * String to use in the HTTP User-Agent field - */ - data->set.useragent = va_arg(param, char *); - break; - - case CURLOPT_HTTPHEADER: - /* - * Set a list with HTTP headers to use (or replace internals with) - */ - data->set.headers = va_arg(param, struct curl_slist *); - break; - - case CURLOPT_HTTP200ALIASES: - /* - * Set a list of aliases for HTTP 200 in response header - */ - data->set.http200aliases = va_arg(param, struct curl_slist *); - break; - -#if !defined(CURL_DISABLE_COOKIES) - case CURLOPT_COOKIE: - /* - * Cookie string to send to the remote server in the request. - */ - data->set.cookie = va_arg(param, char *); - break; - - case CURLOPT_COOKIEFILE: - /* - * Set cookie file to read and parse. Can be used multiple times. - */ - argptr = (char *)va_arg(param, void *); - if(argptr) { - struct curl_slist *cl; - /* append the cookie file name to the list of file names, and deal with - them later */ - cl = curl_slist_append(data->change.cookielist, argptr); - - if(!cl) - return CURLE_OUT_OF_MEMORY; - - data->change.cookielist = cl; - } - break; - - case CURLOPT_COOKIEJAR: - /* - * Set cookie file name to dump all cookies to when we're done. - */ - data->set.cookiejar = (char *)va_arg(param, void *); - - /* - * Activate the cookie parser. This may or may not already - * have been made. - */ - data->cookies = Curl_cookie_init(data, NULL, data->cookies, - data->set.cookiesession); - break; - - case CURLOPT_COOKIESESSION: - /* - * Set this option to TRUE to start a new "cookie session". It will - * prevent the forthcoming read-cookies-from-file actions to accept - * cookies that are marked as being session cookies, as they belong to a - * previous session. - * - * In the original Netscape cookie spec, "session cookies" are cookies - * with no expire date set. RFC2109 describes the same action if no - * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds - * a 'Discard' action that can enforce the discard even for cookies that - * have a Max-Age. - * - * We run mostly with the original cookie spec, as hardly anyone implements - * anything else. - */ - data->set.cookiesession = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_COOKIELIST: - argptr = va_arg(param, char *); - - if(argptr == NULL) - break; - - if(strequal(argptr, "ALL")) { - /* clear all cookies */ - Curl_cookie_clearall(data->cookies); - break; - } - else if(strequal(argptr, "SESS")) { - /* clear session cookies */ - Curl_cookie_clearsess(data->cookies); - break; - } - - if(!data->cookies) - /* if cookie engine was not running, activate it */ - data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); - - argptr = strdup(argptr); - if(!argptr) { - result = CURLE_OUT_OF_MEMORY; - break; - } - - if(checkprefix("Set-Cookie:", argptr)) - /* HTTP Header format line */ - Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL); - - else - /* Netscape format line */ - Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL); - - free(argptr); - break; -#endif /* CURL_DISABLE_COOKIES */ - - case CURLOPT_HTTPGET: - /* - * Set to force us do HTTP GET - */ - if(va_arg(param, long)) { - data->set.httpreq = HTTPREQ_GET; - data->set.upload = FALSE; /* switch off upload */ - data->set.opt_no_body = FALSE; /* this is implied */ - } - break; - - case CURLOPT_HTTP_VERSION: - /* - * This sets a requested HTTP version to be used. The value is one of - * the listed enums in curl/curl.h. - */ - data->set.httpversion = va_arg(param, long); - break; - - case CURLOPT_HTTPPROXYTUNNEL: - /* - * Tunnel operations through the proxy instead of normal proxy use - */ - data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_CUSTOMREQUEST: - /* - * Set a custom string to use as request - */ - data->set.customrequest = va_arg(param, char *); - - /* we don't set - data->set.httpreq = HTTPREQ_CUSTOM; - here, we continue as if we were using the already set type - and this just changes the actual request keyword */ - break; - - case CURLOPT_PROXYPORT: - /* - * Explicitly set HTTP proxy port number. - */ - data->set.proxyport = va_arg(param, long); - break; - - case CURLOPT_HTTPAUTH: - /* - * Set HTTP Authentication type BITMASK. - */ - { - long auth = va_arg(param, long); - /* switch off bits we can't support */ -#ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ -#endif -#ifndef HAVE_GSSAPI - auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */ -#endif - if(!auth) - return CURLE_FAILED_INIT; /* no supported types left! */ - - data->set.httpauth = auth; - } - break; - - case CURLOPT_PROXYAUTH: - /* - * Set HTTP Authentication type BITMASK. - */ - { - long auth = va_arg(param, long); - /* switch off bits we can't support */ -#ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ -#endif -#ifndef HAVE_GSSAPI - auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */ -#endif - if(!auth) - return CURLE_FAILED_INIT; /* no supported types left! */ - - data->set.proxyauth = auth; - } - break; -#endif /* CURL_DISABLE_HTTP */ - - case CURLOPT_PROXY: - /* - * Set proxy server:port to use as HTTP proxy. - * - * If the proxy is set to "" 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 - * to decide for us. - */ - data->set.proxy = va_arg(param, char *); - break; - - case CURLOPT_WRITEHEADER: - /* - * Custom pointer to pass the header write callback function - */ - data->set.writeheader = (void *)va_arg(param, void *); - break; - case CURLOPT_ERRORBUFFER: - /* - * Error buffer provided by the caller to get the human readable - * error string in. - */ - data->set.errorbuffer = va_arg(param, char *); - break; - case CURLOPT_FILE: - /* - * FILE pointer to write to or include in the data write callback - */ - data->set.out = va_arg(param, FILE *); - break; - case CURLOPT_FTPPORT: - /* - * Use FTP PORT, this also specifies which IP address to use - */ - data->set.ftpport = va_arg(param, char *); - data->set.ftp_use_port = (bool)(NULL != data->set.ftpport); - break; - - case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_SSL_CCC: - data->set.ftp_use_ccc = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_SKIP_PASV_IP: - /* - * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the - * bypass of the IP address in PASV responses. - */ - data->set.ftp_skip_ip = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_INFILE: - /* - * FILE pointer to read the file to be uploaded from. Or possibly - * used as argument to the read callback. - */ - data->set.in = va_arg(param, FILE *); - break; - case CURLOPT_INFILESIZE: - /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. - */ - data->set.infilesize = va_arg(param, long); - break; - case CURLOPT_INFILESIZE_LARGE: - /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. - */ - data->set.infilesize = va_arg(param, curl_off_t); - break; - case CURLOPT_LOW_SPEED_LIMIT: - /* - * The low speed limit that if transfers are below this for - * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. - */ - data->set.low_speed_limit=va_arg(param, long); - break; - case CURLOPT_MAX_SEND_SPEED_LARGE: - /* - * The max speed limit that sends transfer more than - * CURLOPT_MAX_SEND_PER_SECOND bytes per second the transfer is - * throttled.. - */ - data->set.max_send_speed=va_arg(param, curl_off_t); - break; - case CURLOPT_MAX_RECV_SPEED_LARGE: - /* - * The max speed limit that sends transfer more than - * CURLOPT_MAX_RECV_PER_SECOND bytes per second the transfer is - * throttled.. - */ - data->set.max_recv_speed=va_arg(param, curl_off_t); - break; - case CURLOPT_LOW_SPEED_TIME: - /* - * The low speed time that if transfers are below the set - * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. - */ - data->set.low_speed_time=va_arg(param, long); - break; - case CURLOPT_URL: - /* - * The URL to fetch. - */ - if(data->change.url_alloc) { - /* the already set URL is allocated, free it first! */ - free(data->change.url); - data->change.url_alloc=FALSE; - } - data->set.set_url = va_arg(param, char *); - data->change.url = data->set.set_url; - data->change.url_changed = TRUE; - break; - case CURLOPT_PORT: - /* - * The port number to use when getting the URL - */ - data->set.use_port = va_arg(param, long); - break; - case CURLOPT_TIMEOUT: - /* - * The maximum time you allow curl to use for a single transfer - * operation. - */ - data->set.timeout = va_arg(param, long); - break; - case CURLOPT_CONNECTTIMEOUT: - /* - * The maximum time you allow curl to use to connect. - */ - data->set.connecttimeout = va_arg(param, long); - break; - - case CURLOPT_USERPWD: - /* - * user:password to use in the operation - */ - data->set.userpwd = va_arg(param, char *); - break; - case CURLOPT_POSTQUOTE: - /* - * List of RAW FTP commands to use after a transfer - */ - data->set.postquote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_PREQUOTE: - /* - * List of RAW FTP commands to use prior to RETR (Wesley Laxton) - */ - data->set.prequote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_QUOTE: - /* - * List of RAW FTP commands to use before a transfer - */ - data->set.quote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_PROGRESSFUNCTION: - /* - * Progress callback function - */ - data->set.fprogress = va_arg(param, curl_progress_callback); - if(data->set.fprogress) - data->progress.callback = TRUE; /* no longer internal */ - else - data->progress.callback = FALSE; /* NULL enforces internal */ - - break; - case CURLOPT_PROGRESSDATA: - /* - * Custom client data to pass to the progress callback - */ - data->set.progress_client = va_arg(param, void *); - break; - case CURLOPT_PROXYUSERPWD: - /* - * user:password needed to use the proxy - */ - data->set.proxyuserpwd = va_arg(param, char *); - break; - case CURLOPT_RANGE: - /* - * What range of the file you want to transfer - */ - data->set.set_range = va_arg(param, char *); - break; - case CURLOPT_RESUME_FROM: - /* - * Resume transfer at the give file position - */ - data->set.set_resume_from = va_arg(param, long); - break; - case CURLOPT_RESUME_FROM_LARGE: - /* - * Resume transfer at the give file position - */ - data->set.set_resume_from = va_arg(param, curl_off_t); - break; - case CURLOPT_DEBUGFUNCTION: - /* - * stderr write callback. - */ - data->set.fdebug = va_arg(param, curl_debug_callback); - /* - * if the callback provided is NULL, it'll use the default callback - */ - break; - case CURLOPT_DEBUGDATA: - /* - * Set to a void * that should receive all error writes. This - * defaults to CURLOPT_STDERR for normal operations. - */ - data->set.debugdata = va_arg(param, void *); - break; - case CURLOPT_STDERR: - /* - * Set to a FILE * that should receive all error writes. This - * defaults to stderr for normal operations. - */ - data->set.err = va_arg(param, FILE *); - if(!data->set.err) - data->set.err = stderr; - break; - case CURLOPT_HEADERFUNCTION: - /* - * Set header write callback - */ - data->set.fwrite_header = va_arg(param, curl_write_callback); - break; - case CURLOPT_WRITEFUNCTION: - /* - * Set data write callback - */ - data->set.fwrite = va_arg(param, curl_write_callback); - if(!data->set.fwrite) - /* When set to NULL, reset to our internal default function */ - data->set.fwrite = (curl_write_callback)fwrite; - break; - case CURLOPT_READFUNCTION: - /* - * Read data callback - */ - data->set.fread = va_arg(param, curl_read_callback); - if(!data->set.fread) - /* When set to NULL, reset to our internal default function */ - data->set.fread = (curl_read_callback)fread; - break; - case CURLOPT_CONV_FROM_NETWORK_FUNCTION: - /* - * "Convert from network encoding" callback - */ - data->set.convfromnetwork = va_arg(param, curl_conv_callback); - break; - case CURLOPT_CONV_TO_NETWORK_FUNCTION: - /* - * "Convert to network encoding" callback - */ - data->set.convtonetwork = va_arg(param, curl_conv_callback); - break; - case CURLOPT_CONV_FROM_UTF8_FUNCTION: - /* - * "Convert from UTF-8 encoding" callback - */ - data->set.convfromutf8 = va_arg(param, curl_conv_callback); - break; - case CURLOPT_IOCTLFUNCTION: - /* - * I/O control callback. Might be NULL. - */ - data->set.ioctl = va_arg(param, curl_ioctl_callback); - break; - case CURLOPT_IOCTLDATA: - /* - * I/O control data pointer. Might be NULL. - */ - data->set.ioctl_client = va_arg(param, void *); - break; - case CURLOPT_SSLCERT: - /* - * String that holds file name of the SSL certificate to use - */ - data->set.cert = va_arg(param, char *); - break; - case CURLOPT_SSLCERTTYPE: - /* - * String that holds file type of the SSL certificate to use - */ - data->set.cert_type = va_arg(param, char *); - break; - case CURLOPT_SSLKEY: - /* - * String that holds file name of the SSL certificate to use - */ - data->set.key = va_arg(param, char *); - break; - case CURLOPT_SSLKEYTYPE: - /* - * String that holds file type of the SSL certificate to use - */ - data->set.key_type = va_arg(param, char *); - break; - case CURLOPT_SSLKEYPASSWD: - /* - * String that holds the SSL private key password. - */ - data->set.key_passwd = va_arg(param, char *); - break; - case CURLOPT_SSLENGINE: - /* - * String that holds the SSL crypto engine. - */ - argptr = va_arg(param, char *); - if (argptr && argptr[0]) - result = Curl_ssl_set_engine(data, argptr); - break; - - case CURLOPT_SSLENGINE_DEFAULT: - /* - * flag to set engine as default. - */ - result = Curl_ssl_set_engine_default(data); - break; - case CURLOPT_CRLF: - /* - * Kludgy option to enable CRLF conversions. Subject for removal. - */ - data->set.crlf = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_INTERFACE: - /* - * Set what interface or address/hostname to bind the socket to when - * performing an operation and thus what from-IP your connection will use. - */ - data->set.device = va_arg(param, char *); - break; - case CURLOPT_LOCALPORT: - /* - * Set what local port to bind the socket to when performing an operation. - */ - data->set.localport = (unsigned short) va_arg(param, long); - break; - case CURLOPT_LOCALPORTRANGE: - /* - * Set number of local ports to try, starting with CURLOPT_LOCALPORT. - */ - data->set.localportrange = (int) va_arg(param, long); - break; - case CURLOPT_KRB4LEVEL: - /* - * A string that defines the krb4 security level. - */ - data->set.krb4_level = va_arg(param, char *); - data->set.krb4 = (bool)(NULL != data->set.krb4_level); - break; - case CURLOPT_SSL_VERIFYPEER: - /* - * Enable peer SSL verifying. - */ - data->set.ssl.verifypeer = va_arg(param, long); - break; - case CURLOPT_SSL_VERIFYHOST: - /* - * Enable verification of the CN contained in the peer certificate - */ - data->set.ssl.verifyhost = va_arg(param, long); - break; - case CURLOPT_SSL_CTX_FUNCTION: - /* - * Set a SSL_CTX callback - */ - data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); - break; - case CURLOPT_SSL_CTX_DATA: - /* - * Set a SSL_CTX callback parameter pointer - */ - data->set.ssl.fsslctxp = va_arg(param, void *); - break; - case CURLOPT_CAINFO: - /* - * Set CA info for SSL connection. Specify file name of the CA certificate - */ - data->set.ssl.CAfile = va_arg(param, char *); - break; - case CURLOPT_CAPATH: - /* - * Set CA path info for SSL connection. Specify directory name of the CA - * certificates which have been prepared using openssl c_rehash utility. - */ - /* This does not work on windows. */ - data->set.ssl.CApath = va_arg(param, char *); - break; - case CURLOPT_TELNETOPTIONS: - /* - * Set a linked list of telnet options - */ - data->set.telnet_options = va_arg(param, struct curl_slist *); - break; - - case CURLOPT_BUFFERSIZE: - /* - * The application kindly asks for a differently sized receive buffer. - * If it seems reasonable, we'll use it. - */ - data->set.buffer_size = va_arg(param, long); - - if((data->set.buffer_size> (BUFSIZE -1 )) || - (data->set.buffer_size < 1)) - data->set.buffer_size = 0; /* huge internal default */ - - break; - - case CURLOPT_NOSIGNAL: - /* - * The application asks not to set any signal() or alarm() handlers, - * even when using a timeout. - */ - data->set.no_signal = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_SHARE: - { - struct Curl_share *set; - set = va_arg(param, struct Curl_share *); - - /* disconnect from old share, if any */ - if(data->share) { - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); - - if(data->dns.hostcachetype == HCACHE_SHARED) { - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; - } - - if(data->share->cookies == data->cookies) - data->cookies = NULL; - - data->share->dirty--; - - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - data->share = NULL; - } - - /* use new share if it set */ - data->share = set; - if(data->share) { - - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); - - data->share->dirty++; - - if(data->share->hostcache) { - /* use shared host cache, first free the private one if any */ - if(data->dns.hostcachetype == HCACHE_PRIVATE) - Curl_hash_destroy(data->dns.hostcache); - - data->dns.hostcache = data->share->hostcache; - data->dns.hostcachetype = HCACHE_SHARED; - } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(data->share->cookies) { - /* use shared cookie list, first free own one if any */ - if (data->cookies) - Curl_cookie_cleanup(data->cookies); - data->cookies = data->share->cookies; - } -#endif /* CURL_DISABLE_HTTP */ - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - - } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - /* check cookie list is set */ - if(!data->cookies) - data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE ); -#endif /* CURL_DISABLE_HTTP */ - /* check for host cache not needed, - * it will be done by curl_easy_perform */ - } - break; - - case CURLOPT_PROXYTYPE: - /* - * Set proxy type. HTTP/SOCKS4/SOCKS5 - */ - data->set.proxytype = (curl_proxytype)va_arg(param, long); - break; - - case CURLOPT_PRIVATE: - /* - * Set private data pointer. - */ - data->set.private_data = va_arg(param, char *); - break; - - case CURLOPT_MAXFILESIZE: - /* - * Set the maximum size of a file to download. - */ - data->set.max_filesize = va_arg(param, long); - break; - - case CURLOPT_FTP_SSL: - /* - * Make FTP transfers attempt to use SSL/TLS. - */ - data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long); - break; - - case CURLOPT_FTPSSLAUTH: - /* - * Set a specific auth for FTP-SSL transfers. - */ - data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long); - break; - - case CURLOPT_IPRESOLVE: - data->set.ip_version = va_arg(param, long); - break; - - case CURLOPT_MAXFILESIZE_LARGE: - /* - * Set the maximum size of a file to download. - */ - data->set.max_filesize = va_arg(param, curl_off_t); - break; - - case CURLOPT_TCP_NODELAY: - /* - * Enable or disable TCP_NODELAY, which will disable/enable the Nagle - * algorithm - */ - data->set.tcp_nodelay = (bool)(0 != va_arg(param, long)); - break; - - /* - case CURLOPT_SOURCE_URL: - case CURLOPT_SOURCE_USERPWD: - case CURLOPT_SOURCE_QUOTE: - case CURLOPT_SOURCE_PREQUOTE: - case CURLOPT_SOURCE_POSTQUOTE: - These former 3rd party transfer options are deprecated */ - - case CURLOPT_FTP_ACCOUNT: - data->set.ftp_account = va_arg(param, char *); - break; - - case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_CONNECT_ONLY: - /* - * No data transfer, set up connection and let application use the socket - */ - data->set.connect_only = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_ALTERNATIVE_TO_USER: - data->set.ftp_alternative_to_user = va_arg(param, char *); - break; - - case CURLOPT_SOCKOPTFUNCTION: - /* - * socket callback function: called after socket() but before connect() - */ - data->set.fsockopt = va_arg(param, curl_sockopt_callback); - break; - - case CURLOPT_SOCKOPTDATA: - /* - * socket callback data pointer. Might be NULL. - */ - data->set.sockopt_client = va_arg(param, void *); - break; - - case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (bool)(0 != va_arg(param, long)); - break; - - case CURLOPT_SSH_AUTH_TYPES: - data->set.ssh_auth_types = va_arg(param, long); - break; - - case CURLOPT_SSH_PUBLIC_KEYFILE: - /* - * Use this file instead of the $HOME/.ssh/id_dsa.pub file - */ - data->set.ssh_public_key = va_arg(param, char *); - break; - - case CURLOPT_SSH_PRIVATE_KEYFILE: - /* - * Use this file instead of the $HOME/.ssh/id_dsa file - */ - data->set.ssh_private_key = va_arg(param, char *); - break; - - default: - /* unknown tag and its companion, just ignore: */ - result = CURLE_FAILED_INIT; /* correct this */ - break; - } - - return result; -} - -static void conn_free(struct connectdata *conn) -{ - if (!conn) - return; - - /* close possibly still open sockets */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - sclose(conn->sock[SECONDARYSOCKET]); - if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) - sclose(conn->sock[FIRSTSOCKET]); - - Curl_safefree(conn->user); - Curl_safefree(conn->passwd); - Curl_safefree(conn->proxyuser); - Curl_safefree(conn->proxypasswd); - Curl_safefree(conn->allocptr.proxyuserpwd); - Curl_safefree(conn->allocptr.uagent); - Curl_safefree(conn->allocptr.userpwd); - Curl_safefree(conn->allocptr.accept_encoding); - Curl_safefree(conn->allocptr.rangeline); - Curl_safefree(conn->allocptr.ref); - Curl_safefree(conn->allocptr.host); - Curl_safefree(conn->allocptr.cookiehost); - Curl_safefree(conn->ip_addr_str); - Curl_safefree(conn->trailer); - Curl_safefree(conn->host.rawalloc); /* host name buffer */ - Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ - - Curl_llist_destroy(conn->send_pipe, NULL); - Curl_llist_destroy(conn->recv_pipe, NULL); - - /* possible left-overs from the async name resolvers */ -#if defined(USE_ARES) - Curl_safefree(conn->async.hostname); - Curl_safefree(conn->async.os_specific); -#elif defined(CURLRES_THREADED) - Curl_destroy_thread_data(&conn->async); -#endif - - Curl_free_ssl_config(&conn->ssl_config); - - free(conn); /* free all the connection oriented data */ -} - -CURLcode Curl_disconnect(struct connectdata *conn) -{ - struct SessionHandle *data; - if(!conn) - return CURLE_OK; /* this is closed and fine already */ - data = conn->data; - - if(!data) { - DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n")); - return CURLE_OK; - } - -#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST) - /* scan for DNS cache entries still marked as in use */ - Curl_hash_apply(data->hostcache, - NULL, Curl_scan_cache_used); -#endif - - Curl_expire(data, 0); /* shut off timers */ - Curl_hostcache_prune(data); /* kill old DNS cache entries */ - - /* - * The range string is usually freed in curl_done(), but we might - * get here *instead* if we fail prematurely. Thus we need to be able - * to free this resource here as well. - */ - if(data->reqdata.rangestringalloc) { - free(data->reqdata.range); - data->reqdata.rangestringalloc = FALSE; - } - - if((conn->ntlm.state != NTLMSTATE_NONE) || - (conn->proxyntlm.state != NTLMSTATE_NONE)) { - /* Authentication data is a mix of connection-related and sessionhandle- - related stuff. NTLM is connection-related so when we close the shop - we shall forget. */ - data->state.authhost.done = FALSE; - data->state.authhost.picked = - data->state.authhost.want; - - data->state.authproxy.done = FALSE; - data->state.authproxy.picked = - data->state.authproxy.want; - - data->state.authproblem = FALSE; - - Curl_ntlm_cleanup(conn); - } - - if(conn->curl_disconnect) - /* This is set if protocol-specific cleanups should be made */ - conn->curl_disconnect(conn); - - if(-1 != conn->connectindex) { - /* unlink ourselves! */ - infof(data, "Closing connection #%ld\n", conn->connectindex); - if(data->state.connc) - /* only clear the table entry if we still know in which cache we - used to be in */ - data->state.connc->connects[conn->connectindex] = NULL; - } - -#ifdef USE_LIBIDN - if(conn->host.encalloc) - idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed - with idn_free() since this was allocated - by libidn */ - if(conn->proxy.encalloc) - idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be - freed with idn_free() since this was - allocated by libidn */ -#endif - - Curl_ssl_close(conn); - - /* Indicate to all handles on the pipe that we're dead */ - if (IsPipeliningEnabled(data)) { - signalPipeClose(conn->send_pipe); - signalPipeClose(conn->recv_pipe); - } - - conn_free(conn); - - return CURLE_OK; -} - -/* - * This function should return TRUE if the socket is to be assumed to - * be dead. Most commonly this happens when the server has closed the - * connection due to inactivity. - */ -static bool SocketIsDead(curl_socket_t sock) -{ - int sval; - bool ret_val = TRUE; - - sval = Curl_select(sock, CURL_SOCKET_BAD, 0); - if(sval == 0) - /* timeout */ - ret_val = FALSE; - - return ret_val; -} - -static bool IsPipeliningPossible(struct SessionHandle *handle) -{ - if (handle->multi && Curl_multi_canPipeline(handle->multi) && - (handle->set.httpreq == HTTPREQ_GET || - handle->set.httpreq == HTTPREQ_HEAD) && - handle->set.httpversion != CURL_HTTP_VERSION_1_0) - return TRUE; - - return FALSE; -} - -static bool IsPipeliningEnabled(struct SessionHandle *handle) -{ - if (handle->multi && Curl_multi_canPipeline(handle->multi)) - return TRUE; - - return FALSE; -} - -void Curl_addHandleToPipeline(struct SessionHandle *data, - struct curl_llist *pipe) -{ -#ifdef CURLDEBUG - if(!IsPipeliningPossible(data)) { - /* when not pipelined, there MUST be no handle in the list already */ - if(pipe->head) - infof(data, "PIPE when no PIPE supposed!\n"); - } -#endif - Curl_llist_insert_next(pipe, pipe->tail, data); -} - - -int Curl_removeHandleFromPipeline(struct SessionHandle *handle, - struct curl_llist *pipe) -{ - struct curl_llist_element *curr; - - curr = pipe->head; - while (curr) { - if (curr->ptr == handle) { - Curl_llist_remove(pipe, curr, NULL); - return 1; /* we removed a handle */ - } - curr = curr->next; - } - - return 0; -} - -#if 0 /* this code is saved here as it is useful for debugging purposes */ -static void Curl_printPipeline(struct curl_llist *pipe) -{ - struct curl_llist_element *curr; - - curr = pipe->head; - while (curr) { - struct SessionHandle *data = (struct SessionHandle *) curr->ptr; - infof(data, "Handle in pipeline: %s\n", - data->reqdata.path); - curr = curr->next; - } -} -#endif - -bool Curl_isHandleAtHead(struct SessionHandle *handle, - struct curl_llist *pipe) -{ - struct curl_llist_element *curr = pipe->head; - if (curr) { - return (bool)(curr->ptr == handle); - } - - return FALSE; -} - -static void signalPipeClose(struct curl_llist *pipe) -{ - struct curl_llist_element *curr; - - curr = pipe->head; - while (curr) { - struct curl_llist_element *next = curr->next; - struct SessionHandle *data = (struct SessionHandle *) curr->ptr; - -#ifdef CURLDEBUG /* debug-only code */ - if(data->magic != CURLEASY_MAGIC_NUMBER) { - /* MAJOR BADNESS */ - fprintf(stderr, "signalPipeClose() found BAAD easy handle\n"); - } - else -#endif - - data->state.pipe_broke = TRUE; - Curl_llist_remove(pipe, curr, NULL); - curr = next; - } -} - - -/* - * 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. - */ -static bool -ConnectionExists(struct SessionHandle *data, - struct connectdata *needle, - struct connectdata **usethis) -{ - long i; - struct connectdata *check; - bool canPipeline = IsPipeliningPossible(data); - - for(i=0; i< data->state.connc->num; i++) { - bool match = FALSE; - /* - * Note that if we use a HTTP proxy, we check connections to that - * proxy and not to the actual remote server. - */ - check = data->state.connc->connects[i]; - if(!check) - /* NULL pointer means not filled-in entry */ - continue; - - if (check->connectindex == -1) { - check->connectindex = i; /* Set this appropriately since it might have - been set to -1 when the easy was removed - from the multi */ - } - - infof(data, "Examining connection #%ld for reuse\n", check->connectindex); - - if(check->inuse && !canPipeline) { - /* can only happen within multi handles, and means that another easy - handle is using this connection */ - continue; - } - -#ifdef CURLRES_ASYNCH - /* ip_addr_str is NULL only if the resolving of the name hasn't completed - yet and until then we don't re-use this connection */ - if (!check->ip_addr_str) { - infof(data, - "Connection #%ld has not finished name resolve, can't reuse\n", - check->connectindex); - continue; - } -#endif - - if (check->send_pipe->size + - check->recv_pipe->size >= MAX_PIPELINE_LENGTH) { - infof(data, "Connection #%ld has its pipeline full, can't reuse\n", - check->connectindex); - continue; - } - - if (data->state.is_in_pipeline && check->bits.close) { - /* Don't pick a connection that is going to be closed */ - infof(data, "Connection #%ld has been marked for close, can't reuse\n", - check->connectindex); - continue; - } - - if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL)) - /* don't do mixed SSL and non-SSL connections */ - continue; - - if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) { - /* The requested connection does not use a HTTP proxy or it - uses SSL. */ - - if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy) - /* we don't do SSL but the cached connection has a proxy, - then don't match this */ - continue; - - if(strequal(needle->protostr, check->protostr) && - strequal(needle->host.name, check->host.name) && - (needle->remote_port == check->remote_port) ) { - if(needle->protocol & PROT_SSL) { - /* This is SSL, verify that we're using the same - ssl options as well */ - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) { - infof(data, - "Connection #%ld has different SSL parameters, " - "can't reuse\n", - check->connectindex ); - continue; - } - } - if((needle->protocol & PROT_FTP) || - ((needle->protocol & PROT_HTTP) && - (data->state.authhost.want==CURLAUTH_NTLM))) { - /* This is FTP or HTTP+NTLM, verify that we're using the same name - and password as well */ - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) { - /* one of them was different */ - continue; - } - } - match = TRUE; - } - } - else { /* The requested needle connection is using a proxy, - is the checked one using the same? */ - if(check->bits.httpproxy && - strequal(needle->proxy.name, check->proxy.name) && - needle->port == check->port) { - /* This is the same proxy connection, use it! */ - match = TRUE; - } - } - - if(match) { - if (!IsPipeliningEnabled(data)) { - /* The check for a dead socket makes sense only in the - non-pipelining case */ - bool dead = SocketIsDead(check->sock[FIRSTSOCKET]); - if(dead) { - check->data = data; - infof(data, "Connection #%d seems to be dead!\n", i); - - Curl_disconnect(check); /* disconnect resources */ - data->state.connc->connects[i]=NULL; /* nothing here */ - - return FALSE; - } - } - - check->inuse = TRUE; /* mark this as being in use so that no other - handle in a multi stack may nick it */ - - if (canPipeline) { - /* Mark the connection as being in a pipeline */ - check->is_in_pipeline = TRUE; - } - - check->connectindex = i; /* Set this appropriately since it might have - been set to -1 when the easy was removed - from the multi */ - *usethis = check; - return TRUE; /* yes, we found one to use! */ - } - } - - return FALSE; /* no matching connecting exists */ -} - - - -/* - * This function frees/closes a connection in the connection cache. This - * should take the previously set policy into account when deciding which - * of the connections to kill. - */ -static long -ConnectionKillOne(struct SessionHandle *data) -{ - long i; - struct connectdata *conn; - long highscore=-1; - long connindex=-1; - long score; - struct timeval now; - - now = Curl_tvnow(); - - for(i=0; data->state.connc && (i< data->state.connc->num); i++) { - conn = data->state.connc->connects[i]; - - if(!conn || conn->inuse) - continue; - - /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); - - if(score > highscore) { - highscore = score; - connindex = i; - } - } - if(connindex >= 0) { - /* Set the connection's owner correctly */ - conn = data->state.connc->connects[connindex]; - conn->data = data; - - /* the winner gets the honour of being disconnected */ - (void)Curl_disconnect(conn); - - /* clean the array entry */ - data->state.connc->connects[connindex] = NULL; - } - - return connindex; /* return the available index or -1 */ -} - -/* this connection can now be marked 'idle' */ -static void -ConnectionDone(struct connectdata *conn) -{ - conn->inuse = FALSE; - if (!conn->send_pipe && !conn->recv_pipe) - conn->is_in_pipeline = FALSE; -} - -/* - * The given input connection struct pointer is to be stored. If the "cache" - * is already full, we must clean out the most suitable using the previously - * set policy. - * - * The given connection should be unique. That must've been checked prior to - * this call. - */ -static long -ConnectionStore(struct SessionHandle *data, - struct connectdata *conn) -{ - long i; - for(i=0; i< data->state.connc->num; i++) { - if(!data->state.connc->connects[i]) - break; - } - if(i == data->state.connc->num) { - /* there was no room available, kill one */ - i = ConnectionKillOne(data); - if(-1 != i) - infof(data, "Connection (#%d) was killed to make room (holds %d)\n", - i, data->state.connc->num); - else - infof(data, "This connection did not fit in the connection cache\n"); - } - - conn->connectindex = i; /* Make the child know where the pointer to this - particular data is stored. But note that this -1 - if this is not within the cache and this is - probably not checked for everywhere (yet). */ - conn->inuse = TRUE; - if(-1 != i) { - /* Only do this if a true index was returned, if -1 was returned there - is no room in the cache for an unknown reason and we cannot store - this there. - - TODO: make sure we really can work with more handles than positions in - the cache, or possibly we should (allow to automatically) resize the - connection cache when we add more easy handles to a multi handle! - */ - data->state.connc->connects[i] = conn; /* fill in this */ - conn->data = data; - } - - return i; -} - -static CURLcode ConnectPlease(struct SessionHandle *data, - struct connectdata *conn, - struct Curl_dns_entry *hostaddr, - bool *connected) -{ - CURLcode result; - Curl_addrinfo *addr; - char *hostname = conn->bits.httpproxy?conn->proxy.name:conn->host.name; - - infof(data, "About to connect() to %s%s port %d (#%d)\n", - conn->bits.httpproxy?"proxy ":"", - hostname, conn->port, conn->connectindex); - - /************************************************************* - * Connect to server/proxy - *************************************************************/ - result= Curl_connecthost(conn, - hostaddr, - &conn->sock[FIRSTSOCKET], - &addr, - connected); - if(CURLE_OK == result) { - /* All is cool, then we store the current information */ - conn->dns_entry = hostaddr; - conn->ip_addr = addr; - - Curl_store_ip_addr(conn); - - switch(data->set.proxytype) { - case CURLPROXY_SOCKS5: - result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, conn); - break; - case CURLPROXY_HTTP: - /* do nothing here. handled later. */ - break; - case CURLPROXY_SOCKS4: - result = Curl_SOCKS4(conn->proxyuser, conn); - break; - default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - break; - } - } - - return result; -} - -/* - * verboseconnect() displays verbose information after a connect - */ -static void verboseconnect(struct connectdata *conn) -{ - infof(conn->data, "Connected to %s (%s) port %d (#%d)\n", - conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname, - conn->ip_addr_str, conn->port, conn->connectindex); -} - -int Curl_protocol_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if(conn->curl_proto_getsock) - return conn->curl_proto_getsock(conn, socks, numsocks); - return GETSOCK_BLANK; -} - -int Curl_doing_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - if(conn && conn->curl_doing_getsock) - return conn->curl_doing_getsock(conn, socks, numsocks); - return GETSOCK_BLANK; -} - -/* - * We are doing protocol-specific connecting and this is being called over and - * over from the multi interface until the connection phase is done on - * protocol layer. - */ - -CURLcode Curl_protocol_connecting(struct connectdata *conn, - bool *done) -{ - CURLcode result=CURLE_OK; - - if(conn && conn->curl_connecting) { - *done = FALSE; - result = conn->curl_connecting(conn, done); - } - else - *done = TRUE; - - return result; -} - -/* - * We are DOING this is being called over and over from the multi interface - * until the DOING phase is done on protocol layer. - */ - -CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done) -{ - CURLcode result=CURLE_OK; - - if(conn && conn->curl_doing) { - *done = FALSE; - result = conn->curl_doing(conn, done); - } - else - *done = TRUE; - - return result; -} - -/* - * We have discovered that the TCP connection has been successful, we can now - * proceed with some action. - * - */ -CURLcode Curl_protocol_connect(struct connectdata *conn, - bool *protocol_done) -{ - CURLcode result=CURLE_OK; - struct SessionHandle *data = conn->data; - - *protocol_done = FALSE; - - if(conn->bits.tcpconnect && 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 don't know if the protocol is actually done. - - Unless this protocol doesn't have any protocol-connect callback, as - then we know we're done. */ - if(!conn->curl_connecting) - *protocol_done = TRUE; - - return CURLE_OK; - } - - if(!conn->bits.tcpconnect) { - - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ - - if(data->set.verbose) - verboseconnect(conn); - } - - if(!conn->bits.protoconnstart) { - if(conn->curl_connect) { - /* is there a protocol-specific connect() procedure? */ - - /* Set start time here for timeout purposes in the connect procedure, it - is later set again for the progress meter purpose */ - conn->now = Curl_tvnow(); - - /* Call the protocol-specific connect function */ - result = conn->curl_connect(conn, protocol_done); - } - else - *protocol_done = TRUE; - - /* it has started, possibly even completed but that knowledge isn't stored - in this bit! */ - if (!result) - conn->bits.protoconnstart = TRUE; - } - - return result; /* pass back status */ -} - -/* - * Helpers for IDNA convertions. - */ -#ifdef USE_LIBIDN -static bool is_ASCII_name(const char *hostname) -{ - const unsigned char *ch = (const unsigned char*)hostname; - - while (*ch) { - if (*ch++ & 0x80) - return FALSE; - } - return TRUE; -} - -/* - * Check if characters in hostname is allowed in Top Level Domain. - */ -static bool tld_check_name(struct SessionHandle *data, - const char *ace_hostname) -{ - size_t err_pos; - char *uc_name = NULL; - int rc; - - /* Convert (and downcase) ACE-name back into locale's character set */ - rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0); - if (rc != IDNA_SUCCESS) - return (FALSE); - - rc = tld_check_lz(uc_name, &err_pos, NULL); - if (rc == TLD_INVALID) - infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n", -#ifdef HAVE_TLD_STRERROR - tld_strerror((Tld_rc)rc), -#else - "", -#endif - err_pos, uc_name[err_pos], - uc_name[err_pos] & 255); - else if (rc != TLD_SUCCESS) - infof(data, "WARNING: TLD check for %s failed; %s\n", - uc_name, -#ifdef HAVE_TLD_STRERROR - tld_strerror((Tld_rc)rc) -#else - "" -#endif - ); - if (uc_name) - idn_free(uc_name); - return (bool)(rc == TLD_SUCCESS); -} -#endif - -static void fix_hostname(struct SessionHandle *data, - struct connectdata *conn, struct hostname *host) -{ - /* set the name we use to display the host name */ - host->dispname = host->name; - -#ifdef USE_LIBIDN - /************************************************************* - * Check name for non-ASCII and convert hostname to ACE form. - *************************************************************/ - if (!is_ASCII_name(host->name) && - stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - char *ace_hostname = NULL; - int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); - infof (data, "Input domain encoded as `%s'\n", - stringprep_locale_charset ()); - if (rc != IDNA_SUCCESS) - infof(data, "Failed to convert %s to ACE; %s\n", - host->name, Curl_idn_strerror(conn,rc)); - else { - /* tld_check_name() displays a warning if the host name contains - "illegal" characters for this TLD */ - (void)tld_check_name(data, ace_hostname); - - host->encalloc = ace_hostname; - /* change the name pointer to point to the encoded hostname */ - host->name = host->encalloc; - } - } -#else - (void)data; /* never used */ - (void)conn; /* never used */ -#endif -} - -/* - * Parse URL and fill in the relevant members of the connection struct. - */ -static CURLcode ParseURLAndFillConnection(struct SessionHandle *data, - struct connectdata *conn) -{ - char *at; - char *tmp; - - char *path = data->reqdata.path; - - /************************************************************* - * Parse the URL. - * - * We need to parse the url even when using the proxy, because we will need - * the hostname and port in case we are trying to SSL connect through the - * proxy -- and we don't know if we will need to use SSL until we parse the - * url ... - ************************************************************/ - if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]", - conn->protostr, - path)) && strequal(conn->protostr, "file")) { - if(path[0] == '/' && path[1] == '/') { - /* Allow omitted hostname (e.g. file:/). This is not strictly - * speaking a valid file: URL by RFC 1738, but treating file:/ as - * file://localhost/ is similar to how other schemes treat missing - * hostnames. See RFC 1808. */ - - /* This cannot be done with strcpy() in a portable manner, since the - memory areas overlap! */ - memmove(path, path + 2, strlen(path + 2)+1); - } - /* - * we deal with file:/// differently since it supports no - * hostname other than "localhost" and "127.0.0.1", which is unique among - * the URL protocols specified in RFC 1738 - */ - if(path[0] != '/') { - /* the URL included a host name, we ignore host names in file:// URLs - as the standards don't define what to do with them */ - char *ptr=strchr(path, '/'); - if(ptr) { - /* there was a slash present - - RFC1738 (section 3.1, page 5) says: - - The rest of the locator consists of data specific to the scheme, - and is known as the "url-path". It supplies the details of how the - specified resource can be accessed. Note that the "/" between the - host (or port) and the url-path is NOT part of the url-path. - - As most agents use file://localhost/foo to get '/foo' although the - slash preceding foo is a separator and not a slash for the path, - a URL as file://localhost//foo must be valid as well, to refer to - the same file with an absolute path. - */ - - if(ptr[1] && ('/' == ptr[1])) - /* if there was two slashes, we skip the first one as that is then - used truly as a separator */ - ptr++; - - /* This cannot be made with strcpy, as the memory chunks overlap! */ - memmove(path, ptr, strlen(ptr)+1); - } - } - - strcpy(conn->protostr, "file"); /* store protocol string lowercase */ - } - else { - /* clear path */ - path[0]=0; - - if (2 > sscanf(data->change.url, - "%15[^\n:]://%[^\n/]%[^\n]", - conn->protostr, - conn->host.name, path)) { - - /* - * The URL was badly formatted, let's try the browser-style _without_ - * protocol specified like 'http://'. - */ - if((1 > sscanf(data->change.url, "%[^\n/]%[^\n]", - conn->host.name, path)) ) { - /* - * We couldn't even get this format. - */ - failf(data, " malformed"); - return CURLE_URL_MALFORMAT; - } - - /* - * Since there was no protocol part specified, we guess what protocol it - * is based on the first letters of the server name. - */ - - /* Note: if you add a new protocol, please update the list in - * lib/version.c too! */ - - if(checkprefix("FTP.", conn->host.name)) - strcpy(conn->protostr, "ftp"); - else if (checkprefix("DICT.", conn->host.name)) - strcpy(conn->protostr, "DICT"); - else if (checkprefix("LDAP.", conn->host.name)) - strcpy(conn->protostr, "LDAP"); - else { - strcpy(conn->protostr, "http"); - } - - conn->protocol |= PROT_MISSING; /* not given in URL */ - } - } - - /* We search for '?' in the host name (but only on the right side of a - * @-letter to allow ?-letters in username and password) to handle things - * like http://example.com?param= (notice the missing '/'). - */ - at = strchr(conn->host.name, '@'); - if(at) - tmp = strchr(at+1, '?'); - else - tmp = strchr(conn->host.name, '?'); - - if(tmp) { - /* We must insert a slash before the '?'-letter in the URL. If the URL had - a slash after the '?', that is where the path currently begins and the - '?string' is still part of the host name. - - We must move the trailing part from the host name and put it first in - the path. And have it all prefixed with a slash. - */ - - size_t hostlen = strlen(tmp); - size_t pathlen = strlen(path); - - /* move the existing path plus the zero byte forward, to make room for - the host-name part */ - memmove(path+hostlen+1, path, pathlen+1); - - /* now copy the trailing host part in front of the existing path */ - memcpy(path+1, tmp, hostlen); - - path[0]='/'; /* prepend the missing slash */ - - *tmp=0; /* now cut off the hostname at the ? */ - } - else if(!path[0]) { - /* if there's no path set, use a single slash */ - strcpy(path, "/"); - } - - /* If the URL is malformatted (missing a '/' after hostname before path) we - * insert a slash here. The only letter except '/' we accept to start a path - * is '?'. - */ - if(path[0] == '?') { - /* We need this function to deal with overlapping memory areas. We know - that the memory area 'path' points to is 'urllen' bytes big and that - is bigger than the path. Use +1 to move the zero byte too. */ - memmove(&path[1], path, strlen(path)+1); - path[0] = '/'; - } - - /* - * So if the URL was A://B/C, - * conn->protostr is A - * conn->host.name is B - * data->reqdata.path is /C - */ - - return CURLE_OK; -} - -static void llist_dtor(void *user, void *element) -{ - (void)user; - (void)element; - /* Do nothing */ -} - - -/** - * CreateConnection() sets up a new connectdata struct, or re-uses an already - * 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 - * already resolved. - * - * @param data The sessionhandle pointer - * @param in_connect is set to the next connection data pointer - * @param addr is set to the new dns entry for this connection. If this - * connection is re-used it will be NULL. - * @param async is set TRUE/FALSE depending on the nature of this lookup - * @return CURLcode - * @see SetupConnection() - * - * *NOTE* this function assigns the conn->data pointer! - */ - -static CURLcode CreateConnection(struct SessionHandle *data, - struct connectdata **in_connect, - struct Curl_dns_entry **addr, - bool *async) -{ - - char *tmp; - CURLcode result=CURLE_OK; - struct connectdata *conn; - struct connectdata *conn_temp = NULL; - size_t urllen; - struct Curl_dns_entry *hostaddr; -#if defined(HAVE_ALARM) && !defined(USE_ARES) - unsigned int prev_alarm=0; -#endif - char endbracket; - char user[MAX_CURL_USER_LENGTH]; - char passwd[MAX_CURL_PASSWORD_LENGTH]; - int rc; - bool reuse; - char *proxy; - bool proxy_alloc = FALSE; - -#ifndef USE_ARES -#ifdef SIGALRM -#ifdef HAVE_SIGACTION - struct sigaction keep_sigact; /* store the old struct here */ - bool keep_copysig=FALSE; /* did copy it? */ -#else -#ifdef HAVE_SIGNAL - void (*keep_sigact)(int); /* store the old handler here */ -#endif /* HAVE_SIGNAL */ -#endif /* HAVE_SIGACTION */ -#endif /* SIGALRM */ -#endif /* USE_ARES */ - - *addr = NULL; /* nothing yet */ - *async = FALSE; - - /************************************************************* - * Check input data - *************************************************************/ - - if(!data->change.url) - return CURLE_URL_MALFORMAT; - - /* First, split up the current URL in parts so that we can use the - parts for checking against the already present connections. In order - to not have to modify everything at once, we allocate a temporary - connection data struct and fill in for comparison purposes. */ - - conn = (struct connectdata *)calloc(sizeof(struct connectdata), 1); - if(!conn) { - *in_connect = NULL; /* clear the pointer */ - return CURLE_OUT_OF_MEMORY; - } - /* We must set the return variable as soon as possible, so that our - parent can cleanup any possible allocs we may have done before - any failure */ - *in_connect = conn; - - /* and we setup a few fields in case we end up actually using this struct */ - - conn->data = data; /* Setup the association between this connection - and the SessionHandle */ - - conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->connectindex = -1; /* no index */ - - conn->bits.httpproxy = (bool)(data->set.proxy /* http proxy or not */ - && *data->set.proxy - && (data->set.proxytype == CURLPROXY_HTTP)); - proxy = data->set.proxy; /* if global proxy is set, this is it */ - - /* 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. */ - conn->bits.close = TRUE; - - conn->readchannel_inuse = FALSE; - conn->writechannel_inuse = FALSE; - - conn->read_pos = 0; - conn->buf_len = 0; - - /* Initialize the pipeline lists */ - conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - - /* Store creation time to help future close decision making */ - conn->created = Curl_tvnow(); - - /* range status */ - data->reqdata.use_range = (bool)(NULL != data->set.set_range); - - data->reqdata.range = data->set.set_range; /* clone the range setting */ - data->reqdata.resume_from = data->set.set_resume_from; - - conn->bits.user_passwd = (bool)(NULL != data->set.userpwd); - conn->bits.proxy_user_passwd = (bool)(NULL != data->set.proxyuserpwd); - conn->bits.no_body = data->set.opt_no_body; - conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; - conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; - conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; - - /* This initing continues below, see the comment "Continue connectdata - * initialization here" */ - - /*********************************************************** - * We need to allocate memory to store the path in. We get the size of the - * full URL to be sure, and we need to make it at least 256 bytes since - * other parts of the code will rely on this fact - ***********************************************************/ -#define LEAST_PATH_ALLOC 256 - urllen=strlen(data->change.url); - if(urllen < LEAST_PATH_ALLOC) - urllen=LEAST_PATH_ALLOC; - - if (!data->set.source_url /* 3rd party FTP */ - && data->reqdata.pathbuffer) { - /* Free the old buffer */ - free(data->reqdata.pathbuffer); - } - - /* - * We malloc() the buffers below urllen+2 to make room for to possibilities: - * 1 - an extra terminating zero - * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used) - */ - - data->reqdata.pathbuffer=(char *)malloc(urllen+2); - if(NULL == data->reqdata.pathbuffer) - return CURLE_OUT_OF_MEMORY; /* really bad error */ - data->reqdata.path = data->reqdata.pathbuffer; - - conn->host.rawalloc=(char *)malloc(urllen+2); - if(NULL == conn->host.rawalloc) - return CURLE_OUT_OF_MEMORY; - - conn->host.name = conn->host.rawalloc; - conn->host.name[0] = 0; - - result = ParseURLAndFillConnection(data, conn); - if (result != CURLE_OK) { - return result; - } - - /************************************************************* - * Take care of proxy authentication stuff - *************************************************************/ - if(conn->bits.proxy_user_passwd) { - char proxyuser[MAX_CURL_USER_LENGTH]=""; - char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; - - sscanf(data->set.proxyuserpwd, - "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", - proxyuser, proxypasswd); - - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - if(!conn->proxyuser) - return CURLE_OUT_OF_MEMORY; - - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - if(!conn->proxypasswd) - return CURLE_OUT_OF_MEMORY; - } - -#ifndef CURL_DISABLE_HTTP - /************************************************************* - * Detect what (if any) proxy to use - *************************************************************/ - if(!conn->bits.httpproxy) { - /* If proxy was not specified, we check for default proxy environment - * variables, to enable i.e Lynx compliance: - * - * http_proxy=http://some.server.dom:port/ - * https_proxy=http://some.server.dom:port/ - * ftp_proxy=http://some.server.dom:port/ - * no_proxy=domain1.dom,host.domain2.dom - * (a comma-separated list of hosts which should - * not be proxied, or an asterisk to override - * all proxy variables) - * all_proxy=http://some.server.dom:port/ - * (seems to exist for the CERN www lib. Probably - * the first to check for.) - * - * For compatibility, the all-uppercase versions of these variables are - * checked if the lowercase versions don't exist. - */ - char *no_proxy=NULL; - char *no_proxy_tok_buf; - char proxy_env[128]; - - no_proxy=curl_getenv("no_proxy"); - if(!no_proxy) - no_proxy=curl_getenv("NO_PROXY"); - - if(!no_proxy || !strequal("*", no_proxy)) { - /* NO_PROXY wasn't specified or it wasn't just an asterisk */ - char *nope; - - nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL; - while(nope) { - size_t namelen; - char *endptr = strchr(conn->host.name, ':'); - if(endptr) - namelen=endptr-conn->host.name; - else - namelen=strlen(conn->host.name); - - if(strlen(nope) <= namelen) { - char *checkn= - conn->host.name + namelen - strlen(nope); - if(checkprefix(nope, checkn)) { - /* no proxy for this host! */ - break; - } - } - nope=strtok_r(NULL, ", ", &no_proxy_tok_buf); - } - if(!nope) { - /* It was not listed as without proxy */ - char *protop = conn->protostr; - char *envp = proxy_env; - char *prox; - - /* Now, build _proxy and check for such a one to use */ - while(*protop) - *envp++ = (char)tolower((int)*protop++); - - /* append _proxy */ - strcpy(envp, "_proxy"); - - /* read the protocol proxy: */ - prox=curl_getenv(proxy_env); - - /* - * We don't try the uppercase version of HTTP_PROXY because of - * security reasons: - * - * When curl is used in a webserver application - * environment (cgi or php), this environment variable can - * be controlled by the web server user by setting the - * http header 'Proxy:' to some value. - * - * This can cause 'internal' http/ftp requests to be - * arbitrarily redirected by any external attacker. - */ - if(!prox && !strequal("http_proxy", proxy_env)) { - /* There was no lowercase variable, try the uppercase version: */ - for(envp = proxy_env; *envp; envp++) - *envp = (char)toupper((int)*envp); - prox=curl_getenv(proxy_env); - } - - if(prox && *prox) { /* don't count "" strings */ - proxy = prox; /* use this */ - } - else { - proxy = curl_getenv("all_proxy"); /* default proxy to use */ - if(!proxy) - proxy=curl_getenv("ALL_PROXY"); - } - - if(proxy && *proxy) { - long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); - /* force this to become HTTP */ - conn->protocol = PROT_HTTP | bits; - - proxy_alloc=TRUE; /* this needs to be freed later */ - conn->bits.httpproxy = TRUE; - } - } /* if (!nope) - it wasn't specified non-proxy */ - } /* NO_PROXY wasn't specified or '*' */ - if(no_proxy) - free(no_proxy); - } /* if not using proxy */ -#endif /* CURL_DISABLE_HTTP */ - - /************************************************************* - * No protocol part in URL was used, add it! - *************************************************************/ - if(conn->protocol&PROT_MISSING) { - /* We're guessing prefixes here and if we're told to use a proxy or if - we're gonna follow a Location: later or... then we need the protocol - part added so that we have a valid URL. */ - char *reurl; - - reurl = aprintf("%s://%s", conn->protostr, data->change.url); - - if(!reurl) - return CURLE_OUT_OF_MEMORY; - - data->change.url = reurl; - data->change.url_alloc = TRUE; /* free this later */ - conn->protocol &= ~PROT_MISSING; /* switch that one off again */ - } - -#ifndef CURL_DISABLE_HTTP - /************************************************************ - * RESUME on a HTTP page is a tricky business. First, let's just check that - * 'range' isn't used, then set the range parameter and leave the resume as - * it is to inform about this situation for later use. We will then - * "attempt" to resume, and if we're talking to a HTTP/1.1 (or later) - * server, we will get the document resumed. If we talk to a HTTP/1.0 - * server, we just fail since we can't rewind the file writing from within - * this function. - ***********************************************************/ - if(data->reqdata.resume_from) { - if(!data->reqdata.use_range) { - /* if it already was in use, we just skip this */ - data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", data->reqdata.resume_from); - if(!data->reqdata.range) - return CURLE_OUT_OF_MEMORY; - data->reqdata.rangestringalloc = TRUE; /* mark as allocated */ - data->reqdata.use_range = 1; /* switch on range usage */ - } - } -#endif - /************************************************************* - * Setup internals depending on protocol - *************************************************************/ - - conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ - - if (strequal(conn->protostr, "HTTP")) { -#ifndef CURL_DISABLE_HTTP - conn->port = PORT_HTTP; - conn->remote_port = PORT_HTTP; - conn->protocol |= PROT_HTTP; - conn->curl_do = Curl_http; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; - conn->curl_done = Curl_http_done; - conn->curl_connect = Curl_http_connect; -#else - failf(data, LIBCURL_NAME - " was built with HTTP disabled, http: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - else if (strequal(conn->protostr, "HTTPS")) { -#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) - - conn->port = PORT_HTTPS; - conn->remote_port = PORT_HTTPS; - conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL; - - conn->curl_do = Curl_http; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; - conn->curl_done = Curl_http_done; - conn->curl_connect = Curl_http_connect; - conn->curl_connecting = Curl_https_connecting; - conn->curl_proto_getsock = Curl_https_getsock; - -#else /* USE_SSL */ - failf(data, LIBCURL_NAME - " was built with SSL disabled, https: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif /* !USE_SSL */ - } - else if(strequal(conn->protostr, "FTP") || - strequal(conn->protostr, "FTPS")) { - -#ifndef CURL_DISABLE_FTP - char *type; - int port = PORT_FTP; - - if(strequal(conn->protostr, "FTPS")) { -#ifdef USE_SSL - conn->protocol |= PROT_FTPS|PROT_SSL; - conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */ - port = PORT_FTPS; -#else - failf(data, LIBCURL_NAME - " was built with SSL disabled, ftps: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif /* !USE_SSL */ - } - - conn->port = port; - conn->remote_port = (unsigned short)port; - conn->protocol |= PROT_FTP; - - if(proxy && *proxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel ftp operations through the proxy, we - switch and use HTTP operations only */ -#ifndef CURL_DISABLE_HTTP - conn->curl_do = Curl_http; - conn->curl_done = Curl_http_done; - conn->protocol = PROT_HTTP; /* switch to HTTP */ -#else - failf(data, "FTP over http proxy requires HTTP support built-in!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - else { - conn->curl_do = Curl_ftp; - conn->curl_do_more = Curl_ftp_nextconnect; - conn->curl_done = Curl_ftp_done; - conn->curl_connect = Curl_ftp_connect; - conn->curl_connecting = Curl_ftp_multi_statemach; - conn->curl_doing = Curl_ftp_doing; - conn->curl_proto_getsock = Curl_ftp_getsock; - conn->curl_doing_getsock = Curl_ftp_getsock; - conn->curl_disconnect = Curl_ftp_disconnect; - } - - data->reqdata.path++; /* don't include the initial slash */ - - /* FTP URLs support an extension like ";type=" that - * we'll try to get now! */ - type=strstr(data->reqdata.path, ";type="); - if(!type) { - type=strstr(conn->host.rawalloc, ";type="); - } - if(type) { - char command; - *type=0; /* it was in the middle of the hostname */ - command = (char)toupper((int)type[6]); - switch(command) { - case 'A': /* ASCII mode */ - data->set.prefer_ascii = TRUE; - break; - case 'D': /* directory mode */ - data->set.ftp_list_only = TRUE; - break; - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->set.prefer_ascii = FALSE; - break; - } - } -#else /* CURL_DISABLE_FTP */ - failf(data, LIBCURL_NAME - " was built with FTP disabled, ftp/ftps: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - else if(strequal(conn->protostr, "TELNET")) { -#ifndef CURL_DISABLE_TELNET - /* telnet testing factory */ - conn->protocol |= PROT_TELNET; - - conn->port = PORT_TELNET; - conn->remote_port = PORT_TELNET; - conn->curl_do = Curl_telnet; - conn->curl_done = Curl_telnet_done; -#else - failf(data, LIBCURL_NAME - " was built with TELNET disabled!"); -#endif - } - else if (strequal(conn->protostr, "DICT")) { -#ifndef CURL_DISABLE_DICT - conn->protocol |= PROT_DICT; - conn->port = PORT_DICT; - conn->remote_port = PORT_DICT; - conn->curl_do = Curl_dict; - /* no DICT-specific done */ - conn->curl_done = (Curl_done_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built with DICT disabled!"); -#endif - } - else if (strequal(conn->protostr, "LDAP")) { -#ifndef CURL_DISABLE_LDAP - conn->protocol |= PROT_LDAP; - conn->port = PORT_LDAP; - conn->remote_port = PORT_LDAP; - conn->curl_do = Curl_ldap; - /* no LDAP-specific done */ - conn->curl_done = (Curl_done_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built with LDAP disabled!"); -#endif - } - else if (strequal(conn->protostr, "FILE")) { -#ifndef CURL_DISABLE_FILE - conn->protocol |= PROT_FILE; - - conn->curl_do = Curl_file; - conn->curl_done = Curl_file_done; - - /* anyway, this is supposed to be the connect function so we better - at least check that the file is present here! */ - result = Curl_file_connect(conn); - - /* Setup a "faked" transfer that'll do nothing */ - if(CURLE_OK == result) { - conn->data = data; - conn->bits.tcpconnect = TRUE; /* we are "connected */ - ConnectionStore(data, conn); - - result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - -1, NULL); /* no upload */ - } - - return result; -#else - failf(data, LIBCURL_NAME - " was built with FILE disabled!"); -#endif - } - else if (strequal(conn->protostr, "TFTP")) { -#ifndef CURL_DISABLE_TFTP - char *type; - conn->socktype = SOCK_DGRAM; /* UDP datagram based */ - conn->protocol |= PROT_TFTP; - conn->port = PORT_TFTP; - conn->remote_port = PORT_TFTP; - conn->curl_connect = Curl_tftp_connect; - conn->curl_do = Curl_tftp; - conn->curl_done = Curl_tftp_done; - /* TFTP URLs support an extension like ";mode=" that - * we'll try to get now! */ - type=strstr(data->reqdata.path, ";mode="); - if(!type) { - type=strstr(conn->host.rawalloc, ";mode="); - } - if(type) { - char command; - *type=0; /* it was in the middle of the hostname */ - command = (char)toupper((int)type[6]); - switch(command) { - case 'A': /* ASCII mode */ - case 'N': /* NETASCII mode */ - data->set.prefer_ascii = TRUE; - break; - case 'O': /* octet mode */ - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->set.prefer_ascii = FALSE; - break; - } - } -#else - failf(data, LIBCURL_NAME - " was built with TFTP disabled!"); -#endif - } - else if (strequal(conn->protostr, "SCP")) { -#ifdef USE_LIBSSH2 - conn->port = PORT_SSH; - conn->remote_port = PORT_SSH; - conn->protocol = PROT_SCP; - conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */ - conn->curl_do = Curl_scp_do; - conn->curl_done = Curl_scp_done; - conn->curl_do_more = (Curl_do_more_func)ZERO_NULL; -#else - failf(data, LIBCURL_NAME - " was built without LIBSSH2, scp: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif - } - else if (strequal(conn->protostr, "SFTP")) { -#ifdef USE_LIBSSH2 - conn->port = PORT_SSH; - conn->remote_port = PORT_SSH; - conn->protocol = PROT_SFTP; - conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */ - conn->curl_do = Curl_sftp_do; - conn->curl_done = Curl_sftp_done; - conn->curl_do_more = (Curl_do_more_func)NULL; -#else - failf(data, LIBCURL_NAME - " was built without LIBSSH2, scp: not supported!"); - return CURLE_UNSUPPORTED_PROTOCOL; -#endif -} -else { - /* We fell through all checks and thus we don't support the specified - protocol */ - failf(data, "Unsupported protocol: %s", conn->protostr); - return CURLE_UNSUPPORTED_PROTOCOL; - } - - if(proxy && *proxy) { - /* If this is supposed to use a proxy, we need to figure out the proxy - host name name, so that we can re-use an existing connection - that may exist registered to the same proxy host. */ - - char *prox_portno; - char *endofprot; - - /* We need to make a duplicate of the proxy so that we can modify the - string safely. If 'proxy_alloc' is TRUE, the string is already - allocated and we can treat it as duplicated. */ - char *proxydup=proxy_alloc?proxy:strdup(proxy); - - /* We use 'proxyptr' to point to the proxy name from now on... */ - char *proxyptr=proxydup; - char *portptr; - char *atsign; - - if(NULL == proxydup) { - failf(data, "memory shortage"); - return CURLE_OUT_OF_MEMORY; - } - - /* We do the proxy host string parsing here. We want the host name and the - * port name. Accept a protocol:// prefix, even though it should just be - * ignored. - */ - - /* Skip the protocol part if present */ - endofprot=strstr(proxyptr, "://"); - if(endofprot) - proxyptr = endofprot+3; - - /* Is there a username and password given in this proxy url? */ - atsign = strchr(proxyptr, '@'); - if(atsign) { - char proxyuser[MAX_CURL_USER_LENGTH]; - char proxypasswd[MAX_CURL_PASSWORD_LENGTH]; - proxypasswd[0] = 0; - - if(1 <= sscanf(proxyptr, - "%" MAX_CURL_USER_LENGTH_TXT"[^:]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", - proxyuser, proxypasswd)) { - CURLcode res = CURLE_OK; - - /* found user and password, rip them out. note that we are - unescaping them, as there is otherwise no way to have a - username or password with reserved characters like ':' in - them. */ - Curl_safefree(conn->proxyuser); - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - - if(!conn->proxyuser) - res = CURLE_OUT_OF_MEMORY; - else { - Curl_safefree(conn->proxypasswd); - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - - if(!conn->proxypasswd) - res = CURLE_OUT_OF_MEMORY; - } - - if(CURLE_OK == res) { - conn->bits.proxy_user_passwd = TRUE; /* enable it */ - atsign = strdup(atsign+1); /* the right side of the @-letter */ - - if(atsign) { - free(proxydup); /* free the former proxy string */ - proxydup = proxyptr = atsign; /* now use this instead */ - } - else - res = CURLE_OUT_OF_MEMORY; - } - - if(res) { - free(proxydup); /* free the allocated proxy string */ - return res; - } - } - } - - /* start scanning for port number at this point */ - portptr = proxyptr; - - /* detect and extract RFC2732-style IPv6-addresses */ - if(*proxyptr == '[') { - char *ptr = ++proxyptr; /* advance beyond the initial bracket */ - while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':'))) - ptr++; - if(*ptr == ']') { - /* yeps, it ended nicely with a bracket as well */ - *ptr = 0; - portptr = ptr+1; - } - /* Note that if this didn't end with a bracket, we still advanced the - * proxyptr first, but I can't see anything wrong with that as no host - * name nor a numeric can legally start with a bracket. - */ - } - - /* Get port number off proxy.server.com:1080 */ - prox_portno = strchr(portptr, ':'); - if (prox_portno) { - *prox_portno = 0x0; /* cut off number from host name */ - prox_portno ++; - /* now set the local port number */ - conn->port = atoi(prox_portno); - } - else if(data->set.proxyport) { - /* None given in the proxy string, then get the default one if it is - given */ - conn->port = data->set.proxyport; - } - - /* now, clone the cleaned proxy host name */ - conn->proxy.rawalloc = strdup(proxyptr); - conn->proxy.name = conn->proxy.rawalloc; - - free(proxydup); /* free the duplicate pointer and not the modified */ - proxy = NULL; /* this may have just been freed */ - if(!conn->proxy.rawalloc) - return CURLE_OUT_OF_MEMORY; - } - - /************************************************************* - * If the protocol is using SSL and HTTP proxy is used, we set - * the tunnel_proxy bit. - *************************************************************/ - if((conn->protocol&PROT_SSL) && conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; - - /************************************************************* - * Take care of user and password authentication stuff - *************************************************************/ - - /* - * Inputs: data->set.userpwd (CURLOPT_USERPWD) - * data->set.fpasswd (CURLOPT_PASSWDFUNCTION) - * data->set.use_netrc (CURLOPT_NETRC) - * conn->host.name - * netrc file - * hard-coded defaults - * - * Outputs: (almost :- all currently undefined) - * conn->bits.user_passwd - non-zero if non-default passwords exist - * conn->user - non-zero length if defined - * conn->passwd - ditto - * conn->host.name - remove user name and password - */ - - /* At this point, we're hoping all the other special cases have - * been taken care of, so conn->host.name is at most - * [user[:password]]@]hostname - * - * We need somewhere to put the embedded details, so do that first. - */ - - user[0] =0; /* to make everything well-defined */ - passwd[0]=0; - - if (conn->protocol & (PROT_FTP|PROT_HTTP|PROT_SCP|PROT_SFTP)) { - /* This is a FTP, HTTP, SCP or SFTP URL, we will now try to extract the - * possible user+password pair in a string like: - * ftp://user:password@ftp.my.site:8021/README */ - char *ptr=strchr(conn->host.name, '@'); - char *userpass = conn->host.name; - if(ptr != NULL) { - /* there's a user+password given here, to the left of the @ */ - - conn->host.name = ++ptr; - - /* So the hostname is sane. Only bother interpreting the - * results if we could care. It could still be wasted - * work because it might be overtaken by the programmatically - * set user/passwd, but doing that first adds more cases here :-( - */ - - if (data->set.use_netrc != CURL_NETRC_REQUIRED) { - /* We could use the one in the URL */ - - conn->bits.user_passwd = 1; /* enable user+password */ - - if(*userpass != ':') { - /* the name is given, get user+password */ - sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", - user, passwd); - } - else - /* no name given, get the password only */ - sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd); - - if(user[0]) { - char *newname=curl_easy_unescape(data, user, 0, NULL); - if(!newname) - return CURLE_OUT_OF_MEMORY; - if(strlen(newname) < sizeof(user)) - strcpy(user, newname); - - /* if the new name is longer than accepted, then just use - the unconverted name, it'll be wrong but what the heck */ - free(newname); - } - if (passwd[0]) { - /* we have a password found in the URL, decode it! */ - char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL); - if(!newpasswd) - return CURLE_OUT_OF_MEMORY; - if(strlen(newpasswd) < sizeof(passwd)) - strcpy(passwd, newpasswd); - - free(newpasswd); - } - } - } - } - - /************************************************************* - * Figure out the remote port number - * - * No matter if we use a proxy or not, we have to figure out the remote - * port number of various reasons. - * - * To be able to detect port number flawlessly, we must not confuse them - * IPv6-specified addresses in the [0::1] style. (RFC2732) - * - * The conn->host.name is currently [user:passwd@]host[:port] where host - * could be a hostname, IPv4 address or IPv6 address. - *************************************************************/ - if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) && - (']' == endbracket)) { - /* this is a RFC2732-style specified IP-address */ - conn->bits.ipv6_ip = TRUE; - - conn->host.name++; /* pass the starting bracket */ - tmp = strchr(conn->host.name, ']'); - *tmp = 0; /* zero terminate */ - tmp++; /* pass the ending bracket */ - if(':' != *tmp) - tmp = NULL; /* no port number available */ - } - else - tmp = strrchr(conn->host.name, ':'); - - if(data->set.use_port && data->state.allow_port) { - /* if set, we use this and ignore the port possibly given in the URL */ - conn->remote_port = (unsigned short)data->set.use_port; - if(tmp) - *tmp = '\0'; /* cut off the name there anyway - if there was a port - number - since the port number is to be ignored! */ - if(conn->bits.httpproxy) { - /* we need to create new URL with the new port number */ - char *url; - - url = aprintf("http://%s:%d%s", conn->host.name, conn->remote_port, - data->reqdata.path); - if(!url) - return CURLE_OUT_OF_MEMORY; - - if(data->change.url_alloc) - free(data->change.url); - - data->change.url = url; - data->change.url_alloc = TRUE; - } - } - else if (tmp) { - /* no CURLOPT_PORT given, extract the one from the URL */ - - char *rest; - unsigned long port; - - port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */ - - if (rest != (tmp+1) && *rest == '\0') { - /* The colon really did have only digits after it, - * so it is either a port number or a mistake */ - - if (port > 0xffff) { /* Single unix standard says port numbers are - * 16 bits long */ - failf(data, "Port number too large: %lu", port); - return CURLE_URL_MALFORMAT; - } - - *tmp = '\0'; /* cut off the name there */ - conn->remote_port = (unsigned short)port; - } - } - - /* Programmatically set password: - * - always applies, if available - * - takes precedence over the values we just set above - * so scribble it over the top. - * User-supplied passwords are assumed not to need unescaping. - * - * user_password is set in "inherit initial knowledge' above, - * so it doesn't have to be set in this block - */ - if (data->set.userpwd != NULL) { - /* the name is given, get user+password */ - sscanf(data->set.userpwd, - "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", - user, passwd); - } - - conn->bits.netrc = FALSE; - if (data->set.use_netrc != CURL_NETRC_IGNORED) { - if(Curl_parsenetrc(conn->host.name, - user, passwd, - data->set.netrc_file)) { - infof(data, "Couldn't find host %s in the " DOT_CHAR - "netrc file, using defaults\n", - conn->host.name); - } - else { - /* set bits.netrc TRUE to remember that we got the name from a .netrc - file, so that it is safe to use even if we followed a Location: to a - different host or similar. */ - conn->bits.netrc = TRUE; - - conn->bits.user_passwd = 1; /* enable user+password */ - } - } - - /* If our protocol needs a password and we have none, use the defaults */ - if ( (conn->protocol & PROT_FTP) && - !conn->bits.user_passwd) { - - conn->user = strdup(CURL_DEFAULT_USER); - conn->passwd = strdup(CURL_DEFAULT_PASSWORD); - /* This is the default password, so DON'T set conn->bits.user_passwd */ - } - else { - /* store user + password, zero-length if not set */ - conn->user = strdup(user); - conn->passwd = strdup(passwd); - } - if(!conn->user || !conn->passwd) - return CURLE_OUT_OF_MEMORY; - - /************************************************************* - * Check the current list of connections to see if we can - * re-use an already existing one or if we have to create a - * new one. - *************************************************************/ - - /* get a cloned copy of the SSL config situation stored in the - connection struct */ - if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) - return CURLE_OUT_OF_MEMORY; - - /* reuse_fresh is TRUE if we are told to use a new connection by force, but - we only acknowledge this option if this is not a re-used connection - already (which happens due to follow-location or during a HTTP - authentication phase). */ - if(data->set.reuse_fresh && !data->state.this_is_a_follow) - reuse = FALSE; - else - reuse = ConnectionExists(data, conn, &conn_temp); - - if(reuse) { - /* - * We already have a connection for this, we got the former connection - * in the conn_temp variable and thus we need to cleanup the one we - * just allocated before we can move along and use the previously - * existing one. - */ - struct connectdata *old_conn = conn; - - if(old_conn->proxy.rawalloc) - free(old_conn->proxy.rawalloc); - - /* free the SSL config struct from this connection struct as this was - allocated in vain and is targeted for destruction */ - Curl_free_ssl_config(&conn->ssl_config); - - conn = conn_temp; /* use this connection from now on */ - - conn->data = old_conn->data; - - /* get the user+password information from the old_conn struct since it may - * be new for this request even when we re-use an existing connection */ - conn->bits.user_passwd = old_conn->bits.user_passwd; - if (conn->bits.user_passwd) { - /* use the new user namd and password though */ - Curl_safefree(conn->user); - Curl_safefree(conn->passwd); - conn->user = old_conn->user; - conn->passwd = old_conn->passwd; - old_conn->user = NULL; - old_conn->passwd = NULL; - } - - conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; - if (conn->bits.proxy_user_passwd) { - /* use the new proxy user name and proxy password though */ - Curl_safefree(conn->proxyuser); - Curl_safefree(conn->proxypasswd); - conn->proxyuser = old_conn->proxyuser; - conn->proxypasswd = old_conn->proxypasswd; - old_conn->proxyuser = NULL; - old_conn->proxypasswd = NULL; - } - - /* host can change, when doing keepalive with a proxy ! */ - if (conn->bits.httpproxy) { - free(conn->host.rawalloc); - conn->host=old_conn->host; - } - - /* get the newly set value, not the old one */ - conn->bits.no_body = old_conn->bits.no_body; - - if (!conn->bits.httpproxy) - free(old_conn->host.rawalloc); /* free the newly allocated name buffer */ - - /* re-use init */ - conn->bits.reuse = TRUE; /* yes, we're re-using here */ - conn->bits.chunk = FALSE; /* always assume not chunked unless told - otherwise */ - - Curl_safefree(old_conn->user); - Curl_safefree(old_conn->passwd); - Curl_safefree(old_conn->proxyuser); - Curl_safefree(old_conn->proxypasswd); - Curl_llist_destroy(old_conn->send_pipe, NULL); - Curl_llist_destroy(old_conn->recv_pipe, NULL); - - free(old_conn); /* we don't need this anymore */ - - /* - * If we're doing a resumed transfer, we need to setup our stuff - * properly. - */ - data->reqdata.resume_from = data->set.set_resume_from; - if (data->reqdata.resume_from) { - if (data->reqdata.rangestringalloc == TRUE) - free(data->reqdata.range); - data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", - data->reqdata.resume_from); - if(!data->reqdata.range) - return CURLE_OUT_OF_MEMORY; - - /* tell ourselves to fetch this range */ - data->reqdata.use_range = TRUE; /* enable range download */ - data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */ - } - else if (data->set.set_range) { - /* There is a range, but is not a resume, useful for random ftp access */ - data->reqdata.range = strdup(data->set.set_range); - if(!data->reqdata.range) - return CURLE_OUT_OF_MEMORY; - data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */ - data->reqdata.use_range = TRUE; /* enable range download */ - } - else - data->reqdata.use_range = FALSE; /* disable range download */ - - *in_connect = conn; /* return this instead! */ - - infof(data, "Re-using existing connection! (#%ld) with host %s\n", - conn->connectindex, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); - } - else { - /* - * This is a brand new connection, so let's store it in the connection - * cache of ours! - */ - ConnectionStore(data, conn); - } - - /* Continue connectdata initialization here. */ - - /* - * - * Inherit the proper values from the urldata struct AFTER we have arranged - * the persistent connection stuff */ - conn->fread = data->set.fread; - conn->fread_in = data->set.in; - - if ((conn->protocol&PROT_HTTP) && - data->set.upload && - (data->set.infilesize == -1) && - (data->set.httpversion != CURL_HTTP_VERSION_1_0)) { - /* HTTP, upload, unknown file size and not HTTP 1.0 */ - conn->bits.upload_chunky = TRUE; - } - else { - /* else, no chunky upload */ - conn->bits.upload_chunky = FALSE; - } - -#ifndef USE_ARES - /************************************************************* - * Set timeout if that is being used, and we're not using an asynchronous - * name resolve. - *************************************************************/ - if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { - /************************************************************* - * Set signal handler to catch SIGALRM - * Store the old value to be able to set it back later! - *************************************************************/ - -#ifdef SIGALRM -#ifdef HAVE_ALARM - long shortest; -#endif -#ifdef HAVE_SIGACTION - struct sigaction sigact; - sigaction(SIGALRM, NULL, &sigact); - keep_sigact = sigact; - keep_copysig = TRUE; /* yes, we have a copy */ - sigact.sa_handler = alarmfunc; -#ifdef SA_RESTART - /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ - sigact.sa_flags &= ~SA_RESTART; -#endif - /* now set the new struct */ - sigaction(SIGALRM, &sigact, NULL); -#else /* HAVE_SIGACTION */ - /* no sigaction(), revert to the much lamer signal() */ -#ifdef HAVE_SIGNAL - keep_sigact = signal(SIGALRM, alarmfunc); -#endif -#endif /* HAVE_SIGACTION */ - - /* We set the timeout on the name resolving phase first, separately from - * the download/upload part to allow a maximum time on everything. This is - * a signal-based timeout, why it won't work and shouldn't be used in - * multi-threaded environments. */ - -#ifdef HAVE_ALARM - shortest = data->set.timeout; /* default to this timeout value */ - if(shortest && data->set.connecttimeout && - (data->set.connecttimeout < shortest)) - /* if both are set, pick the shortest */ - shortest = data->set.connecttimeout; - else if(!shortest) - /* if timeout is not set, use the connect timeout */ - shortest = data->set.connecttimeout; - - /* alarm() makes a signal get sent when the timeout fires off, and that - will abort system calls */ - prev_alarm = alarm((unsigned int) shortest); - /* We can expect the conn->created time to be "now", as that was just - recently set in the beginning of this function and nothing slow - has been done since then until now. */ -#endif -#endif /* SIGALRM */ - } -#endif /* USE_ARES */ - - /************************************************************* - * Resolve the name of the server or proxy - *************************************************************/ - if(conn->bits.reuse) { - /* re-used connection, no resolving is necessary */ - hostaddr = NULL; - /* we'll need to clear conn->dns_entry later in Curl_disconnect() */ - - if (conn->bits.httpproxy) - fix_hostname(data, conn, &conn->host); - } - else { - /* this is a fresh connect */ - - /* set a pointer to the hostname we display */ - fix_hostname(data, conn, &conn->host); - - if(!conn->proxy.name || !*conn->proxy.name) { - /* 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->remote_port; /* it is the same port */ - - /* Resolve target host right on */ - rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr); - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - - else if(!hostaddr) { - failf(data, "Couldn't resolve host '%s'", conn->host.dispname); - result = CURLE_COULDNT_RESOLVE_HOST; - /* don't return yet, we need to clean up the timeout first */ - } - } - else { - /* This is a proxy that hasn't been resolved yet. */ - - /* IDN-fix the proxy name */ - fix_hostname(data, conn, &conn->proxy); - - /* resolve proxy */ - rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr); - - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname); - result = CURLE_COULDNT_RESOLVE_PROXY; - /* don't return yet, we need to clean up the timeout first */ - } - } - } - *addr = hostaddr; - -#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES) - if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { -#ifdef HAVE_SIGACTION - if(keep_copysig) { - /* we got a struct as it looked before, now put that one back nice - and clean */ - sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */ - } -#else -#ifdef HAVE_SIGNAL - /* restore the previous SIGALRM handler */ - signal(SIGALRM, keep_sigact); -#endif -#endif /* HAVE_SIGACTION */ - - /* switch back the alarm() to either zero or to what it was before minus - the time we spent until now! */ - if(prev_alarm) { - /* there was an alarm() set before us, now put it back */ - unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created); - unsigned long alarm_set; - - /* the alarm period is counted in even number of seconds */ - alarm_set = prev_alarm - elapsed_ms/1000; - - if(!alarm_set || - ((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 - won't, and zero would be to switch it off so we never set it to - less than 1! */ - alarm(1); - result = CURLE_OPERATION_TIMEOUTED; - failf(data, "Previous alarm fired off!"); - } - else - alarm((unsigned int)alarm_set); - } - else - alarm(0); /* just shut it off */ - } -#endif - - return result; -} - -/* SetupConnection() is called after the name resolve initiated in - * CreateConnection() is all done. - * - * NOTE: the argument 'hostaddr' is NULL when this function is called for a - * re-used connection. - * - * conn->data MUST already have been setup fine (in CreateConnection) - */ - -static CURLcode SetupConnection(struct connectdata *conn, - struct Curl_dns_entry *hostaddr, - bool *protocol_done) -{ - CURLcode result=CURLE_OK; - struct SessionHandle *data = conn->data; - - Curl_pgrsTime(data, TIMER_NAMELOOKUP); - - if(conn->protocol & PROT_FILE) { - /* There's nothing in this function to setup if we're only doing - a file:// transfer */ - *protocol_done = TRUE; - return result; - } - *protocol_done = FALSE; /* default to not done */ - - /************************************************************* - * Send user-agent to HTTP proxies even if the target protocol - * isn't HTTP. - *************************************************************/ - if((conn->protocol&PROT_HTTP) || conn->bits.httpproxy) { - if(data->set.useragent) { - Curl_safefree(conn->allocptr.uagent); - conn->allocptr.uagent = - aprintf("User-Agent: %s\r\n", data->set.useragent); - if(!conn->allocptr.uagent) - return CURLE_OUT_OF_MEMORY; - } - } - - conn->headerbytecount = 0; - -#ifdef CURL_DO_LINEEND_CONV - data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ -#endif /* CURL_DO_LINEEND_CONV */ - - for(;;) { - /* loop for CURL_SERVER_CLOSED_CONNECTION */ - - if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { - bool connected = FALSE; - - /* Connect only if not already connected! */ - result = ConnectPlease(data, conn, hostaddr, &connected); - - if(connected) { - result = Curl_protocol_connect(conn, protocol_done); - if(CURLE_OK == result) - conn->bits.tcpconnect = TRUE; - } - else - conn->bits.tcpconnect = FALSE; - - /* if the connection was closed by the server while exchanging - authentication information, retry with the new set - authentication information */ - if(conn->bits.proxy_connect_closed) { - /* reset the error buffer */ - if (data->set.errorbuffer) - data->set.errorbuffer[0] = '\0'; - data->state.errorbuf = FALSE; - continue; - } - - if(CURLE_OK != result) - return result; - } - else { - Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ - conn->bits.tcpconnect = TRUE; - *protocol_done = TRUE; - if(data->set.verbose) - verboseconnect(conn); - } - /* Stop the loop now */ - break; - } - - conn->now = Curl_tvnow(); /* time this *after* the connect is done, we - set this here perhaps a second time */ - -#ifdef __EMX__ - /* 20000330 mgs - * the check is quite a hack... - * we're calling _fsetmode to fix the problem with fwrite converting newline - * characters (you get mangled text files, and corrupted binary files when - * you download to stdout and redirect it to a file). */ - - if ((data->set.out)->_handle == NULL) { - _fsetmode(stdout, "b"); - } -#endif - - return CURLE_OK; -} - -CURLcode Curl_connect(struct SessionHandle *data, - struct connectdata **in_connect, - bool *asyncp, - bool *protocol_done) -{ - CURLcode code; - struct Curl_dns_entry *dns; - - *asyncp = FALSE; /* assume synchronous resolves by default */ - - /* call the stuff that needs to be called */ - code = CreateConnection(data, in_connect, &dns, asyncp); - - if(CURLE_OK == code) { - /* no error */ - if(dns || !*asyncp) - /* If an address is available it means that we already have the name - resolved, OR it isn't async. if this is a re-used connection 'dns' - will be NULL here. Continue connecting from here */ - code = SetupConnection(*in_connect, dns, protocol_done); - /* else - response will be received and treated async wise */ - } - - if(CURLE_OK != code) { - /* We're not allowed to return failure with memory left allocated - in the connectdata struct, free those here */ - if(*in_connect) { - Curl_disconnect(*in_connect); /* close the connection */ - *in_connect = NULL; /* return a NULL */ - } - } - else { - if ((*in_connect)->is_in_pipeline) - data->state.is_in_pipeline = TRUE; - } - - return code; -} - -/* Call this function after Curl_connect() has returned async=TRUE and - then a successful name resolve has been received. - - Note: this function disconnects and frees the conn data in case of - resolve failure */ -CURLcode Curl_async_resolved(struct connectdata *conn, - bool *protocol_done) -{ -#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ - defined(USE_THREADING_GETADDRINFO) - CURLcode code = SetupConnection(conn, conn->async.dns, protocol_done); - - if(code) - /* We're not allowed to return failure with memory left allocated - in the connectdata struct, free those here */ - Curl_disconnect(conn); /* close the connection */ - - return code; -#else - (void)conn; - (void)protocol_done; - return CURLE_OK; -#endif -} - - -CURLcode Curl_done(struct connectdata **connp, - CURLcode status, bool premature) /* an error if this is called after an - error was detected */ -{ - CURLcode result; - struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; - - Curl_expire(data, 0); /* stop timer */ - - if(conn->bits.done) - return CURLE_OK; /* Curl_done() has already been called */ - - conn->bits.done = TRUE; /* called just now! */ - - if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && - conn->readchannel_inuse) - conn->readchannel_inuse = FALSE; - if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && - conn->writechannel_inuse) - conn->writechannel_inuse = FALSE; - - /* cleanups done even if the connection is re-used */ - if(data->reqdata.rangestringalloc) { - free(data->reqdata.range); - data->reqdata.rangestringalloc = FALSE; - } - - /* Cleanup possible redirect junk */ - if(data->reqdata.newurl) { - free(data->reqdata.newurl); - data->reqdata.newurl = NULL; - } - - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } - - /* this calls the protocol-specific function pointer previously set */ - if(conn->curl_done) - result = conn->curl_done(conn, status, premature); - else - result = CURLE_OK; - - Curl_pgrsDone(conn); /* done with the operation */ - - /* for ares-using, make sure all possible outstanding requests are properly - cancelled before we proceed */ - ares_cancel(data->state.areschannel); - - /* if data->set.reuse_forbid is TRUE, it means the libcurl client has - forced us to close this no matter what we think. - - 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(data->set.reuse_forbid || conn->bits.close) { - CURLcode res2 = Curl_disconnect(conn); /* close the connection */ - - *connp = NULL; /* to make the caller of this function better detect that - this was actually killed here */ - - /* If we had an error already, make sure we return that one. But - if we got a new error, return that. */ - if(!result && res2) - result = res2; - } - else { - ConnectionDone(conn); /* the connection is no longer in use */ - - /* remember the most recently used connection */ - data->state.lastconnect = conn->connectindex; - - infof(data, "Connection #%ld to host %s left intact\n", - conn->connectindex, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); - } - - return result; -} - -CURLcode Curl_do(struct connectdata **connp, bool *done) -{ - CURLcode result=CURLE_OK; - struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; - - conn->bits.done = FALSE; /* Curl_done() is not called yet */ - conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ - - if(conn->curl_do) { - /* generic protocol-specific function pointer set in curl_connect() */ - result = conn->curl_do(conn, done); - - /* This was formerly done in transfer.c, but we better do it here */ - - if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { - /* This was a re-use of a connection and we got a write error in the - * DO-phase. Then we DISCONNECT this connection and have another attempt - * to CONNECT and then DO again! The retry cannot possibly find another - * connection to re-use, since we only keep one possible connection for - * each. */ - - infof(data, "Re-used connection seems dead, get a new one\n"); - - conn->bits.close = TRUE; /* enforce close of this connection */ - result = Curl_done(&conn, result, FALSE); /* we are so done with this */ - - /* conn may no longer be a good pointer */ - - /* - * According to bug report #1330310. We need to check for - * CURLE_SEND_ERROR here as well. I figure this could happen when the - * request failed on a FTP connection and thus Curl_done() itself tried - * to use the connection (again). Slight Lack of feedback in the report, - * but I don't think this extra check can do much harm. - */ - if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) { - bool async; - bool protocol_done = TRUE; - - /* Now, redo the connect and get a new connection */ - result = Curl_connect(data, connp, &async, &protocol_done); - if(CURLE_OK == result) { - /* We have connected or sent away a name resolve query fine */ - - conn = *connp; /* setup conn to again point to something nice */ - if(async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - result = Curl_wait_for_resolv(conn, NULL); - if(result) - return result; - - /* Resolved, continue with the connection */ - result = Curl_async_resolved(conn, &protocol_done); - if(result) - return result; - } - - /* ... finally back to actually retry the DO phase */ - result = conn->curl_do(conn, done); - } - } - } - } - return result; -} - -CURLcode Curl_do_more(struct connectdata *conn) -{ - CURLcode result=CURLE_OK; - - if(conn->curl_do_more) - result = conn->curl_do_more(conn); - - return result; -} diff --git a/Utilities/cmcurl/url.h b/Utilities/cmcurl/url.h deleted file mode 100644 index 446b3d9..0000000 --- a/Utilities/cmcurl/url.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __URL_H -#define __URL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include /* to make sure we have ap_list */ - -/* - * Prototypes for library-wide functions provided by url.c - */ - -CURLcode Curl_open(struct SessionHandle **curl); -CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, - va_list arg); -CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ -CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, - bool *async, bool *protocol_connect); -CURLcode Curl_async_resolved(struct connectdata *conn, - bool *protocol_connect); -CURLcode Curl_do(struct connectdata **, bool *done); -CURLcode Curl_do_more(struct connectdata *); -CURLcode Curl_done(struct connectdata **, CURLcode, bool premature); -CURLcode Curl_disconnect(struct connectdata *); -CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); -CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); -CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); -void Curl_safefree(void *ptr); - -/* create a connection cache */ -struct conncache *Curl_mk_connc(int type, int amount); -/* free a connection cache */ -void Curl_rm_connc(struct conncache *c); -/* Change number of entries of a connection cache */ -CURLcode Curl_ch_connc(struct SessionHandle *data, - struct conncache *c, - long newamount); - -int Curl_protocol_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); -int Curl_doing_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - -void Curl_addHandleToPipeline(struct SessionHandle *handle, - struct curl_llist *pipe); -int Curl_removeHandleFromPipeline(struct SessionHandle *handle, - struct curl_llist *pipe); -bool Curl_isHandleAtHead(struct SessionHandle *handle, - struct curl_llist *pipe); - -void Curl_close_connections(struct SessionHandle *data); - -#if 0 -CURLcode Curl_protocol_fdset(struct connectdata *conn, - fd_set *read_fd_set, - fd_set *write_fd_set, - int *max_fdp); -CURLcode Curl_doing_fdset(struct connectdata *conn, - fd_set *read_fd_set, - fd_set *write_fd_set, - int *max_fdp); -#endif - -#endif diff --git a/Utilities/cmcurl/urldata.h b/Utilities/cmcurl/urldata.h deleted file mode 100644 index 46d956d..0000000 --- a/Utilities/cmcurl/urldata.h +++ /dev/null @@ -1,1340 +0,0 @@ -#ifndef __URLDATA_H -#define __URLDATA_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -/* This file is for lib internal stuff */ - -#include "setup.h" - -#define PORT_FTP 21 -#define PORT_FTPS 990 -#define PORT_TELNET 23 -#define PORT_HTTP 80 -#define PORT_HTTPS 443 -#define PORT_DICT 2628 -#define PORT_LDAP 389 -#define PORT_TFTP 69 -#define PORT_SSH 22 - -#define DICT_MATCH "/MATCH:" -#define DICT_MATCH2 "/M:" -#define DICT_MATCH3 "/FIND:" -#define DICT_DEFINE "/DEFINE:" -#define DICT_DEFINE2 "/D:" -#define DICT_DEFINE3 "/LOOKUP:" - -#define CURL_DEFAULT_USER "anonymous" -#define CURL_DEFAULT_PASSWORD "curl_by_daniel@haxx.se" - -#include "cookie.h" -#include "formdata.h" - -#ifdef USE_SSLEAY -#ifdef USE_OPENSSL -#include "openssl/rsa.h" -#include "openssl/crypto.h" -#include "openssl/x509.h" -#include "openssl/pem.h" -#include "openssl/ssl.h" -#include "openssl/err.h" -#ifdef HAVE_OPENSSL_ENGINE_H -#include -#endif -#ifdef HAVE_OPENSSL_PKCS12_H -#include -#endif -#else /* SSLeay-style includes */ -#include "rsa.h" -#include "crypto.h" -#include "x509.h" -#include "pem.h" -#include "ssl.h" -#include "err.h" -#endif /* USE_OPENSSL */ -#endif /* USE_SSLEAY */ - -#ifdef USE_GNUTLS -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "timeval.h" - -#ifdef HAVE_ZLIB_H -#include /* for content-encoding */ -#endif - -#ifdef USE_ARES -#include -#endif - -#include - -#include "http_chunks.h" /* for the structs and enum stuff */ -#include "hostip.h" -#include "hash.h" -#include "splay.h" - -#ifdef HAVE_GSSAPI -# ifdef HAVE_GSSGNU -# include -# elif defined HAVE_GSSMIT -# include -# include -# else -# include -# endif -#endif - -#ifdef HAVE_LIBSSH2_H -#include -#include -#endif /* HAVE_LIBSSH2_H */ - -/* Download buffer size, keep it fairly big for speed reasons */ -#undef BUFSIZE -#define BUFSIZE CURL_MAX_WRITE_SIZE - -/* Initial size of the buffer to store headers in, it'll be enlarged in case - of need. */ -#define HEADERSIZE 256 - -#define CURLEASY_MAGIC_NUMBER 0xc0dedbad - -/* Just a convenience macro to get the larger value out of two given. - We prefix with CURL to prevent name collisions. */ -#define CURLMAX(x,y) ((x)>(y)?(x):(y)) - -#ifdef HAVE_KRB4 -/* Types needed for krb4-ftp connections */ -struct krb4buffer { - void *data; - size_t size; - size_t index; - int eof_flag; -}; -enum protection_level { - prot_clear, - prot_safe, - prot_confidential, - prot_private -}; -#endif - -/* 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; - -/* struct for data related to each SSL connection */ -struct ssl_connect_data { - bool use; /* use ssl encrypted communications TRUE/FALSE */ -#ifdef USE_SSLEAY - /* these ones requires specific SSL-types */ - SSL_CTX* ctx; - SSL* handle; - X509* server_cert; - ssl_connect_state connecting_state; -#endif /* USE_SSLEAY */ -#ifdef USE_GNUTLS - gnutls_session session; - gnutls_certificate_credentials cred; -#endif /* USE_GNUTLS */ -}; - -struct ssl_config_data { - long version; /* what version the client wants to use */ - long certverifyresult; /* result from the certificate verification */ - long verifypeer; /* set TRUE if this is desired */ - long verifyhost; /* 0: no verify - 1: check that CN exists - 2: CN must match hostname */ - char *CApath; /* DOES NOT WORK ON WINDOWS */ - char *CAfile; /* cerficate to verify peer against */ - char *random_file; /* path to file containing "random" data */ - char *egdsocket; /* path to file containing the EGD daemon socket */ - char *cipher_list; /* list of ciphers to use */ - long numsessions; /* SSL session id cache size */ - curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ - void *fsslctxp; /* parameter for call back */ - bool sessionid; /* cache session IDs or not */ -}; - -/* information stored about one single SSL session */ -struct curl_ssl_session { - char *name; /* host name for which this ID was used */ - void *sessionid; /* as returned from the SSL layer */ - size_t idsize; /* if known, otherwise 0 */ - long age; /* just a number, the higher the more recent */ - unsigned short remote_port; /* remote port to connect to */ - struct ssl_config_data ssl_config; /* setup for this session */ -}; - -/* Struct used for Digest challenge-response authentication */ -struct digestdata { - char *nonce; - char *cnonce; - char *realm; - int algo; - bool stale; /* set true for re-negotiation */ - char *opaque; - char *qop; - char *algorithm; - int nc; /* nounce count */ -}; - -typedef enum { - NTLMSTATE_NONE, - NTLMSTATE_TYPE1, - NTLMSTATE_TYPE2, - NTLMSTATE_TYPE3, - NTLMSTATE_LAST -} curlntlm; - -#ifdef USE_WINDOWS_SSPI -/* When including these headers, you must define either SECURITY_WIN32 - * or SECURITY_KERNEL, indicating who is compiling the code. - */ -#define SECURITY_WIN32 1 -#include -#include -#include -#endif - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) -#include -#endif - -/* Struct used for NTLM challenge-response authentication */ -struct ntlmdata { - curlntlm state; -#ifdef USE_WINDOWS_SSPI - CredHandle handle; - CtxtHandle c_handle; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - int has_handles; - void *type_2; - int n_type_2; -#else - unsigned int flags; - unsigned char nonce[8]; -#endif -}; - -#ifdef HAVE_GSSAPI -struct negotiatedata { - bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */ - const char* protocol; /* "GSS-Negotiate" or "Negotiate" */ - OM_uint32 status; - gss_ctx_id_t context; - gss_name_t server_name; - gss_buffer_desc output_token; -}; -#endif - -/**************************************************************************** - * HTTP unique setup - ***************************************************************************/ -struct HTTP { - struct FormData *sendit; - curl_off_t postsize; /* off_t to handle large file sizes */ - char *postdata; - - const char *p_pragma; /* Pragma: string */ - const char *p_accept; /* Accept: string */ - curl_off_t readbytecount; - curl_off_t writebytecount; - - /* For FORM posting */ - struct Form form; - struct Curl_chunker chunk; - - struct back { - curl_read_callback fread; /* backup storage for fread pointer */ - void *fread_in; /* backup storage for fread_in pointer */ - char *postdata; - curl_off_t postsize; - } backup; - - enum { - HTTPSEND_NADA, /* init */ - HTTPSEND_REQUEST, /* sending a request */ - HTTPSEND_BODY, /* sending body */ - HTTPSEND_LAST /* never use this */ - } sending; - - void *send_buffer; /* used if the request couldn't be sent in one chunk, - points to an allocated send_buffer struct */ -}; - -/**************************************************************************** - * FTP unique setup - ***************************************************************************/ -typedef enum { - FTP_STOP, /* do nothing state, stops the state machine */ - FTP_WAIT220, /* waiting for the initial 220 response immediately after - a connect */ - FTP_AUTH, - FTP_USER, - FTP_PASS, - FTP_ACCT, - FTP_PBSZ, - FTP_PROT, - FTP_CCC, - FTP_PWD, - FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ - FTP_RETR_PREQUOTE, - FTP_STOR_PREQUOTE, - FTP_POSTQUOTE, - FTP_CWD, /* change dir */ - 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 */ - FTP_RETR_TYPE, /* set type when about to RETR a file */ - FTP_STOR_TYPE, /* set type when about to STOR a file */ - FTP_SIZE, /* get the remote file's size for head-like request */ - FTP_RETR_SIZE, /* get the remote file's size for RETR */ - FTP_STOR_SIZE, /* get the size for (resumed) STOR */ - FTP_REST, /* when used to check if the server supports it in head-like */ - FTP_RETR_REST, /* when asking for "resume" in for RETR */ - FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */ - FTP_PASV, /* generic state for PASV and EPSV, check count1 */ - FTP_LIST, /* generic state for LIST, NLST or a custom list command */ - FTP_RETR, - FTP_STOR, /* generic state for STOR and APPE */ - FTP_QUIT, - FTP_LAST /* never used */ -} ftpstate; - -typedef enum { - FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */ - FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */ - FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */ -} curl_ftpfile; - -/* This FTP struct is used in the SessionHandle. All FTP data that is - connection-oriented must be in FTP_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is - used. */ -struct FTP { - curl_off_t *bytecountp; - char *user; /* user name string */ - char *passwd; /* password string */ - char *urlpath; /* the originally given path part of the URL */ - char *file; /* decoded file */ - bool no_transfer; /* nothing was transfered, (possibly because a resumed - transfer already was complete) */ - curl_off_t downloadsize; -}; - -/* ftp_conn is used for striuct connection-oriented data in the connectdata - struct */ -struct ftp_conn { - char *entrypath; /* the PWD reply when we logged on */ - char **dirs; /* realloc()ed array for path components */ - int dirdepth; /* number of entries used in the 'dirs' array */ - int diralloc; /* number of entries allocated for the 'dirs' array */ - char *cache; /* data cache between getresponse()-calls */ - curl_off_t cache_size; /* size of cache in bytes */ - bool dont_check; /* Set to TRUE to prevent the final (post-transfer) - file size and 226/250 status check. It should still - read the line, just ignore the result. */ - long response_time; /* When no timeout is given, this is the amount of - seconds we await for an FTP response. Initialized - in Curl_ftp_connect() */ - bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If - the connection has timed out or been closed, this - should be FALSE when it gets to Curl_ftp_quit() */ - bool cwddone; /* if it has been determined that the proper CWD combo - already has been done */ - bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent - caching the current directory */ - char *prevpath; /* conn->path from the previous transfer */ - char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a - and others (A/I or zero) */ - size_t nread_resp; /* number of bytes currently read of a server response */ - char *linestart_resp; /* line start pointer for the FTP server response - reader function */ - - 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 */ - char *sendthis; /* allocated pointer to a buffer that is to be sent to the - ftp server */ - size_t sendleft; /* number of bytes left to send from the sendthis buffer */ - size_t sendsize; /* total size of the sendthis buffer */ - struct timeval response; /* set to Curl_tvnow() when a command has been sent - off, used to time-out response reading */ - ftpstate state; /* always use ftp.c:state() to change state! */ -}; - -struct SSHPROTO { - curl_off_t *bytecountp; - char *user; - char *passwd; - char *path; /* the path we operate on */ - char *homedir; - char *errorstr; -#ifdef USE_LIBSSH2 - LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ - LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ - LIBSSH2_SFTP *sftp_session; /* SFTP handle */ - LIBSSH2_SFTP_HANDLE *sftp_handle; -#endif /* USE_LIBSSH2 */ -}; - - -/**************************************************************************** - * FILE unique setup - ***************************************************************************/ -struct FILEPROTO { - char *path; /* the path we operate on */ - char *freepath; /* pointer to the allocated block we must free, this might - differ from the 'path' pointer */ - int fd; /* open file descriptor to read from! */ -}; - -/* - * Boolean values that concerns this connection. - */ -struct ConnectBits { - bool close; /* if set, we close the connection after this request */ - bool reuse; /* if set, this is a re-used connection */ - bool chunk; /* if set, this is a chunked transfer-encoding */ - bool httpproxy; /* if set, this transfer is done through a http proxy */ - bool user_passwd; /* do we use user+password for this connection? */ - bool proxy_user_passwd; /* user+password for the proxy? */ - bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6 - IP address */ - bool ipv6; /* we communicate with a site using an IPv6 address */ - - bool do_more; /* this is set TRUE if the ->curl_do_more() function is - supposed to be called, after ->curl_do() */ - - bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding - on upload */ - bool getheader; /* TRUE if header parsing is wanted */ - - bool forbidchunk; /* used only to explicitly forbid chunk-upload for - specific upload buffers. See readmoredata() in - http.c for details. */ - - bool tcpconnect; /* the TCP layer (or simimlar) is connected, this is set - the first time on the first connect function call */ - bool protoconnstart;/* the protocol layer has STARTED its operation after - the TCP layer connect */ - - bool retry; /* this connection is about to get closed and then - re-attempted at another connection. */ - bool no_body; /* CURLOPT_NO_BODY (or similar) was set */ - bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy. - This is implicit when SSL-protocols are used through - proxies, but can also be enabled explicitly by - apps */ - bool 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. */ - bool rewindaftersend;/* TRUE when the sending couldn't be stopped even - though it will be discarded. When the whole send - operation is done, we must call the data rewind - callback. */ - bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out - EPSV doesn't work we disable it for the forthcoming - requests */ - - bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out - EPRT doesn't work we disable it for the forthcoming - requests */ - bool netrc; /* name+password provided by netrc */ - - bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response. - Required to determine whether to look for trailers - in case of Transfer-Encoding: chunking */ - bool done; /* set to FALSE when Curl_do() is called and set to TRUE - when Curl_done() is called, to prevent Curl_done() to - get invoked twice when the multi interface is - used. */ - bool stream_was_rewound; /* Indicates that the stream was rewound after a - request read past the end of its response byte - boundary */ - bool proxy_connect_closed; /* set true if a proxy disconnected the - connection in a CONNECT request with auth, so - that libcurl should reconnect and continue. */ -}; - -struct hostname { - char *rawalloc; /* allocated "raw" version of the name */ - char *encalloc; /* allocated IDN-encoded version of the name */ - char *name; /* name to use internally, might be encoded, might be raw */ - char *dispname; /* name to display, as 'name' might be encoded */ -}; - -/* - * Flags on the keepon member of the Curl_transfer_keeper - */ - -#define KEEP_NONE 0 -#define KEEP_READ 1 /* there is or may be data to read */ -#define KEEP_WRITE 2 /* there is or may be data to write */ -#define KEEP_READ_HOLD 4 /* when set, no reading should be done but there - might still be data to read */ -#define KEEP_WRITE_HOLD 8 /* when set, no writing should be done but there - might still be data to write */ - -/* - * This struct is all the previously local variables from Curl_perform() moved - * to struct to allow the function to return and get re-invoked better without - * losing state. - */ - -struct Curl_transfer_keeper { - - /** Values copied over from the HandleData struct each time on init **/ - - curl_off_t size; /* -1 if unknown at this point */ - curl_off_t *bytecountp; /* return number of bytes read or NULL */ - - curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0 - means unlimited */ - curl_off_t *writebytecountp; /* return number of bytes written or NULL */ - - /** End of HandleData struct copies **/ - - curl_off_t bytecount; /* total number of bytes read */ - curl_off_t writebytecount; /* number of bytes written */ - - struct timeval start; /* transfer started at this time */ - struct timeval now; /* current time */ - bool header; /* incoming data has HTTP header */ - enum { - HEADER_NORMAL, /* no bad header at all */ - HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest - is normal data */ - HEADER_ALLBAD /* all was believed to be header */ - } badheader; /* the header was deemed bad and will be - written as body */ - int headerline; /* counts header lines to better track the - first one */ - char *hbufp; /* points at *end* of header line */ - size_t hbuflen; - char *str; /* within buf */ - char *str_start; /* within buf */ - char *end_ptr; /* within buf */ - char *p; /* within headerbuff */ - bool content_range; /* set TRUE if Content-Range: was found */ - curl_off_t offset; /* possible resume offset read from the - Content-Range: header */ - int httpcode; /* error code from the 'HTTP/1.? XXX' line */ - int httpversion; /* the HTTP version*10 */ - struct timeval start100; /* time stamp to wait for the 100 code from */ - bool write_after_100_header; /* TRUE = we enable the write after we - received a 100-continue/timeout or - FALSE = directly */ - bool wait100_after_headers; /* TRUE = after the request-headers have been - sent off properly, we go into the wait100 - state, FALSE = don't */ - int content_encoding; /* What content encoding. sec 3.5, RFC2616. */ - -#define IDENTITY 0 /* No encoding */ -#define DEFLATE 1 /* zlib delfate [RFC 1950 & 1951] */ -#define GZIP 2 /* gzip algorithm [RFC 1952] */ -#define COMPRESS 3 /* Not handled, added for completeness */ - -#ifdef HAVE_LIBZ - bool zlib_init; /* True if zlib already initialized; - undefined if Content-Encoding header. */ - z_stream z; /* State structure for zlib. */ -#endif - - time_t timeofdoc; - long bodywrites; - - char *buf; - char *uploadbuf; - curl_socket_t maxfd; - - int keepon; - - bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload - and we're uploading the last chunk */ - - bool ignorebody; /* we read a response-body but we ignore it! */ - bool ignorecl; /* This HTTP response has no body so we ignore the Content- - Length: header */ -}; - -#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ - defined(USE_THREADING_GETADDRINFO) -struct Curl_async { - char *hostname; - int port; - struct Curl_dns_entry *dns; - bool done; /* set TRUE when the lookup is complete */ - int status; /* if done is TRUE, this is the status from the callback */ - void *os_specific; /* 'struct thread_data' for Windows */ -}; -#endif - -#define FIRSTSOCKET 0 -#define SECONDARYSOCKET 1 - -/* These function pointer types are here only to allow easier typecasting - within the source when we need to cast between data pointers (such as NULL) - and function pointers. */ -typedef CURLcode (*Curl_do_more_func)(struct connectdata *); -typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool); - - -/* - * Store's request specific data in the easy handle (SessionHandle). - * Previously, these members were on the connectdata struct but since - * a conn struct may now be shared between different SessionHandles, - * we store connection-specific data here. - * - */ -struct HandleData { - char *pathbuffer;/* allocated buffer to store the URL's path part in */ - char *path; /* path to use, points to somewhere within the pathbuffer - area */ - - char *newurl; /* This can only be set if a Location: was in the - document headers */ - - /* This struct is inited when needed */ - struct Curl_transfer_keeper keep; - - /* '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; - - curl_off_t size; /* -1 if unknown at this point */ - curl_off_t *bytecountp; /* return number of bytes read or NULL */ - - curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0 - means unlimited */ - curl_off_t *writebytecountp; /* return number of bytes written or NULL */ - - bool use_range; - bool rangestringalloc; /* the range string is malloc()'ed */ - - char *range; /* range, if used. See README for detailed specification on - this syntax. */ - curl_off_t resume_from; /* continue [ftp] transfer from here */ - - /* Protocol specific data */ - - union { - struct HTTP *http; - struct HTTP *https; /* alias, just for the sake of being more readable */ - struct FTP *ftp; - void *tftp; /* private for tftp.c-eyes only */ - struct FILEPROTO *file; - void *telnet; /* private for telnet.c-eyes only */ - void *generic; - struct SSHPROTO *ssh; - } proto; -}; - -/* - * The connectdata struct contains all fields and variables that should be - * unique for an entire connection. - */ -struct connectdata { - /* 'data' is the CURRENT SessionHandle using this connection -- take great - caution that this might very well vary between different times this - connection is used! */ - struct SessionHandle *data; - - bool inuse; /* This is a marker for the connection cache logic. If this is - TRUE this handle is being used by an easy handle and cannot - be used by any other easy handle without careful - consideration (== only for pipelining). */ - - /**** Fields set when inited and not modified again */ - long connectindex; /* what index in the connection cache connects index this - particular struct has */ - long protocol; /* PROT_* flags concerning the protocol set */ -#define PROT_MISSING (1<<0) -#define PROT_HTTP (1<<2) -#define PROT_HTTPS (1<<3) -#define PROT_FTP (1<<4) -#define PROT_TELNET (1<<5) -#define PROT_DICT (1<<6) -#define PROT_LDAP (1<<7) -#define PROT_FILE (1<<8) -#define PROT_FTPS (1<<9) -#define PROT_SSL (1<<10) /* protocol requires SSL */ -#define PROT_TFTP (1<<11) -#define PROT_SCP (1<<12) -#define PROT_SFTP (1<<13) - -#define PROT_CLOSEACTION PROT_FTP /* these ones need action before socket - close */ - - /* '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 - Curl_done(). This entry will be NULL if the connection is re-used as then - there is no name resolve done. */ - struct Curl_dns_entry *dns_entry; - - /* 'ip_addr' is the particular IP we connected to. It points to a struct - within the DNS cache, so this pointer is only valid as long as the DNS - cache entry remains locked. It gets unlocked in Curl_done() */ - Curl_addrinfo *ip_addr; - - /* 'ip_addr_str' is the ip_addr data as a human readable malloc()ed string. - It remains available as long as the connection does, which is longer than - the ip_addr itself. Set with Curl_store_ip_addr() when ip_addr has been - set. */ - char *ip_addr_str; - - char protostr[16]; /* store the protocol string in this buffer */ - int socktype; /* SOCK_STREAM or SOCK_DGRAM */ - - struct hostname host; - struct hostname proxy; - - long port; /* which port to use locally */ - unsigned short remote_port; /* what remote port to connect to, - not the proxy port! */ - - long headerbytecount; /* only count received headers */ - long deductheadercount; /* this amount of bytes doesn't count when we check - if anything has been transfered 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 */ - - char *user; /* user name string, allocated */ - char *passwd; /* password string, allocated */ - - char *proxyuser; /* proxy user name string, allocated */ - char *proxypasswd; /* proxy password string, allocated */ - - struct timeval now; /* "current" time */ - struct timeval created; /* creation time */ - curl_socket_t sock[2]; /* two sockets, the second is used for the data - transfer when doing FTP */ - - struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ - struct ssl_config_data ssl_config; - - struct ConnectBits bits; /* various state-flags for this connection */ - - /* These two functions MUST be set by the curl_connect() function to be - be protocol dependent */ - CURLcode (*curl_do)(struct connectdata *, bool *done); - Curl_done_func curl_done; - - /* If the curl_do() function is better made in two halves, this - * curl_do_more() function will be called afterwards, if set. For example - * for doing the FTP stuff after the PASV/PORT command. - */ - Curl_do_more_func curl_do_more; - - /* 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 doesn't complete, the caller - * should call the curl_connecting() function until it is. - */ - CURLcode (*curl_connect)(struct connectdata *, bool *done); - - /* See above. Currently only used for FTP. */ - CURLcode (*curl_connecting)(struct connectdata *, bool *done); - CURLcode (*curl_doing)(struct connectdata *, bool *done); - - /* Called from the multi interface during the PROTOCONNECT phase, and it - should then return a proper fd set */ - int (*curl_proto_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* Called from the multi interface during the DOING phase, and it should - then return a proper fd set */ - int (*curl_doing_getsock)(struct connectdata *conn, - curl_socket_t *socks, - int numsocks); - - /* This function *MAY* be set to a protocol-dependent function that is run - * by the curl_disconnect(), as a step in the disconnection. - */ - CURLcode (*curl_disconnect)(struct connectdata *); - - /* This function *MAY* be set to a protocol-dependent function that is run - * in the curl_close() function if protocol-specific cleanups are required. - */ - CURLcode (*curl_close)(struct connectdata *); - - /**** curl_get() phase fields */ - - curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ - curl_socket_t writesockfd; /* socket to write to, it may very - well be the same we read from. - CURL_SOCKET_BAD disables */ - - /** Dynamicly allocated strings, may need to be freed before this **/ - /** struct is killed. **/ - struct dynamically_allocated_data { - char *proxyuserpwd; /* free later if not NULL! */ - char *uagent; /* free later if not NULL! */ - char *accept_encoding; /* free later if not NULL! */ - char *userpwd; /* free later if not NULL! */ - char *rangeline; /* free later if not NULL! */ - char *ref; /* free later if not NULL! */ - char *host; /* free later if not NULL */ - char *cookiehost; /* free later if not NULL */ - } allocptr; - - int sec_complete; /* if krb4 is enabled for this connection */ -#ifdef HAVE_KRB4 - enum protection_level command_prot; - enum protection_level data_prot; - enum protection_level request_data_prot; - size_t buffer_size; - struct krb4buffer in_buffer, out_buffer; - void *app_data; - const struct Curl_sec_client_mech *mech; - struct sockaddr_in local_addr; -#endif - - bool readchannel_inuse; /* whether the read channel is in use by an easy - handle */ - bool writechannel_inuse; /* whether the write channel is in use by an easy - handle */ - bool is_in_pipeline; /* TRUE if this connection is in a pipeline */ - - struct curl_llist *send_pipe; /* List of handles waiting to - send on this pipeline */ - struct curl_llist *recv_pipe; /* List of handles waiting to read - their responses on this pipeline */ - - char master_buffer[BUFSIZE]; /* The master buffer for this connection. */ - size_t read_pos; /* Current read position in the master buffer */ - size_t buf_len; /* Length of the buffer?? */ - - - /*************** Request - specific items ************/ - - /* previously this was in the urldata struct */ - curl_read_callback fread; /* function that reads the input */ - void *fread_in; /* pointer to pass to the fread() above */ - - struct ntlmdata ntlm; /* NTLM differs from other authentication schemes - because it authenticates connections, not - single requests! */ - struct ntlmdata proxyntlm; /* NTLM data for proxy */ - - char syserr_buf [256]; /* buffer for Curl_strerror() */ - -#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ - defined(USE_THREADING_GETADDRINFO) - /* data used for the asynch name resolve callback */ - struct Curl_async async; -#endif - - /* These three are used for chunked-encoding trailer support */ - char *trailer; /* allocated buffer to store trailer in */ - int trlMax; /* allocated buffer size */ - int trlPos; /* index of where to store data */ - - union { - struct ftp_conn ftpc; - } proto; -}; - -/* The end of connectdata. */ - -/* - * Struct to keep statistical and informational data. - */ -struct PureInfo { - int httpcode; /* Recent HTTP or FTP response code */ - int httpproxycode; - int httpversion; - long filetime; /* If requested, this is might get set. Set to -1 if the time - was unretrievable. We cannot have this of type time_t, - since time_t is unsigned on several platforms such as - OpenVMS. */ - long header_size; /* size of read header(s) in bytes */ - long request_size; /* the amount of bytes sent in the request(s) */ - - long proxyauthavail; - long httpauthavail; - - long numconnects; /* how many new connection did libcurl created */ - - char *contenttype; /* the content type of the object */ -}; - - -struct Progress { - long lastshow; /* time() of the last displayed progress meter or NULL to - force redraw at next call */ - curl_off_t size_dl; /* total expected size */ - curl_off_t size_ul; /* total expected size */ - curl_off_t downloaded; /* transfered so far */ - curl_off_t uploaded; /* transfered so far */ - - curl_off_t current_speed; /* uses the currently fastest transfer */ - - bool callback; /* set when progress callback is used */ - int width; /* screen width at download start */ - int flags; /* see progress.h */ - - double timespent; - - curl_off_t dlspeed; - curl_off_t ulspeed; - - double t_nslookup; - double t_connect; - double t_pretransfer; - double t_starttransfer; - double t_redirect; - - struct timeval start; - struct timeval t_startsingle; -#define CURR_TIME (5+1) /* 6 entries for 5 seconds */ - - curl_off_t speeder[ CURR_TIME ]; - struct timeval speeder_time[ CURR_TIME ]; - int speeder_c; -}; - -typedef enum { - HTTPREQ_NONE, /* first in list */ - HTTPREQ_GET, - HTTPREQ_POST, - HTTPREQ_POST_FORM, /* we make a difference internally */ - HTTPREQ_PUT, - HTTPREQ_HEAD, - HTTPREQ_CUSTOM, - HTTPREQ_LAST /* last in list */ -} Curl_HttpReq; - -/* - * Values that are generated, temporary or calculated internally for a - * "session handle" must be defined within the 'struct UrlState'. This struct - * will be used within the SessionHandle struct. When the 'SessionHandle' - * struct is cloned, this data MUST NOT be copied. - * - * Remember that any "state" information goes globally for the curl handle. - * Session-data MUST be put in the connectdata struct and here. */ -#define MAX_CURL_USER_LENGTH 256 -#define MAX_CURL_PASSWORD_LENGTH 256 -#define MAX_CURL_USER_LENGTH_TXT "255" -#define MAX_CURL_PASSWORD_LENGTH_TXT "255" - -struct auth { - long want; /* Bitmask set to the authentication methods wanted by the app - (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ - long picked; - long avail; /* bitmask for what the server reports to support for this - resource */ - bool done; /* TRUE when the auth phase is done and ready to do the *actual* - request */ - bool multi; /* TRUE if this is not yet authenticated but within the auth - multipass negotiation */ - -}; - -struct conncache { - /* 'connects' will be an allocated array with pointers. If the pointer is - set, it holds an allocated connection. */ - struct connectdata **connects; - long num; /* number of entries of the 'connects' array */ - enum { - CONNCACHE_PRIVATE, /* used for an easy handle alone */ - CONNCACHE_MULTI /* shared within a multi handle */ - } type; -}; - - -struct UrlState { - enum { - Curl_if_none, - Curl_if_easy, - Curl_if_multi - } used_interface; - - struct conncache *connc; /* points to the connection cache this handle - uses */ - - /* buffers to store authentication data in, as parsed from input options */ - struct timeval keeps_speed; /* for the progress meter really */ - - long lastconnect; /* index of most recent connect or -1 if undefined */ - - char *headerbuff; /* allocated buffer to store headers in */ - size_t headersize; /* size of the allocation */ - - char buffer[BUFSIZE+1]; /* download buffer */ - char uploadbuffer[BUFSIZE+1]; /* upload buffer */ - curl_off_t current_speed; /* the ProgressShow() funcion sets this, - bytes / second */ - bool this_is_a_follow; /* this is a followed Location: request */ - - bool is_in_pipeline; /* Indicates whether this handle is part of a pipeline */ - - char *first_host; /* 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() data. - */ - - struct curl_ssl_session *session; /* array of 'numsessions' size */ - long sessionage; /* number of the most recent session */ - - char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */ - bool errorbuf; /* Set to TRUE if the error buffer is already filled in. - This must be set to FALSE every time _easy_perform() is - called. */ - int os_errno; /* filled in with errno whenever an error occurs */ -#ifdef HAVE_SIGNAL - /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ - void (*prev_signal)(int sig); -#endif - bool allow_port; /* Is set.use_port allowed to take effect or not. This - is always set TRUE when curl_easy_perform() is called. */ - - struct digestdata digest; - struct digestdata proxydigest; - -#ifdef HAVE_GSSAPI - struct negotiatedata negotiate; -#endif - - struct auth authhost; - struct auth authproxy; - - bool authproblem; /* TRUE if there's some problem authenticating */ - -#ifdef USE_ARES - ares_channel areschannel; /* for name resolves */ -#endif - -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *engine; -#endif /* USE_SSLEAY */ - struct timeval expiretime; /* set this with Curl_expire() only */ - struct Curl_tree timenode; /* for the splay stuff */ - - /* a place to store the most recenlty set FTP entrypath */ - char *most_recent_ftp_entrypath; - - /* set after initial USER failure, to prevent an authentication loop */ - bool ftp_trying_alternative; - - bool expect100header; /* TRUE if we added Expect: 100-continue */ - - bool pipe_broke; /* TRUE if the connection we were pipelined on broke - and we need to restart from the beginning */ - bool cancelled; /* TRUE if the request was cancelled */ - -#ifndef WIN32 -/* do FTP line-end conversions on most platforms */ -#define CURL_DO_LINEEND_CONV - /* for FTP downloads: track CRLF sequences that span blocks */ - bool prev_block_had_trailing_cr; - /* for FTP downloads: how many CRLFs did we converted to LFs? */ - curl_off_t crlf_conversions; -#endif - /* If set to non-NULL, there's a connection in a shared connection cache - that uses this handle so we can't kill this SessionHandle just yet but - must keep it around and add it to the list of handles to kill once all - its connections are gone */ - void *shared_conn; - bool closed; /* set to TRUE when curl_easy_cleanup() has been called on this - handle, but it is kept around as mentioned for - shared_conn */ -}; - - -/* - * This 'DynamicStatic' struct defines dynamic states that actually change - * values in the 'UserDefined' area, which MUST be taken into consideration - * if the UserDefined struct is cloned or similar. You can probably just - * copy these, but each one indicate a special action on other data. - */ - -struct DynamicStatic { - char *url; /* work URL, copied from UserDefined */ - bool url_alloc; /* URL string is malloc()'ed */ - bool url_changed; /* set on CURL_OPT_URL, used to detect if the URL was - changed after the connect phase, as we allow callback - to change it and if so, we reconnect to use the new - URL instead */ - char *referer; /* referer string */ - bool referer_alloc; /* referer sting is malloc()ed */ - struct curl_slist *cookielist; /* list of cookie files set by - curl_easy_setopt(COOKIEFILE) calls */ -}; - -/* - * This 'UserDefined' struct must only contain data that is set once to go - * for many (perhaps) independent connections. Values that are generated or - * calculated internally for the "session handle" MUST be defined within the - * 'struct UrlState' instead. The only exceptions MUST note the changes in - * the 'DynamicStatic' struct. - */ -struct Curl_one_easy; /* declared and used only in multi.c */ -struct Curl_multi; /* declared and used only in multi.c */ - -struct UserDefined { - FILE *err; /* the stderr user data goes here */ - void *debugdata; /* the data that will be passed to fdebug */ - char *errorbuffer; /* store failure messages in here */ - char *proxyuserpwd; /* Proxy , if used */ - long proxyport; /* If non-zero, use this port number by default. If the - proxy string features a ":[port]" that one will override - this. */ - void *out; /* the fetched file goes here */ - void *in; /* the uploaded file is read from here */ - void *writeheader; /* write the header to this if non-NULL */ - char *set_url; /* what original URL to work on */ - char *proxy; /* proxy to use */ - long use_port; /* which port to use (when not using default) */ - char *userpwd; /* , if used */ - long httpauth; /* what kind of HTTP authentication to use (bitmask) */ - long proxyauth; /* what kind of proxy authentication to use (bitmask) */ - char *set_range; /* range, if used. See README for detailed specification - on this syntax. */ - long followlocation; /* as in HTTP Location: */ - long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 - for infinity */ - char *set_referer; /* custom string */ - bool free_referer; /* set TRUE if 'referer' points to a string we - allocated */ - char *useragent; /* User-Agent string */ - char *encoding; /* Accept-Encoding string */ - char *postfields; /* if POST, set the fields' values here */ - curl_off_t postfieldsize; /* if POST, this might have a size to use instead - of strlen(), and then the data *may* be binary - (contain zero bytes) */ - char *ftpport; /* port to send with the FTP PORT command */ - char *device; /* local network interface/address to use */ - unsigned short localport; /* local port number to bind to */ - int localportrange; /* number of additional port numbers to test in case the - 'localport' one can't be bind()ed */ - curl_write_callback fwrite; /* function that stores the output */ - curl_write_callback fwrite_header; /* function that stores headers */ - curl_read_callback fread; /* function that reads the input */ - curl_progress_callback fprogress; /* function for progress information */ - curl_debug_callback fdebug; /* function that write informational data */ - curl_ioctl_callback ioctl; /* function for I/O control */ - curl_sockopt_callback fsockopt; /* function for setting socket options */ - void *sockopt_client; /* pointer to pass to the socket options callback */ - - /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ - /* function to convert from the network encoding: */ - curl_conv_callback convfromnetwork; - /* function to convert to the network encoding: */ - curl_conv_callback convtonetwork; - /* function to convert from UTF-8 encoding: */ - curl_conv_callback convfromutf8; - - void *progress_client; /* pointer to pass to the progress callback */ - void *ioctl_client; /* pointer to pass to the ioctl callback */ - long timeout; /* in seconds, 0 means no timeout */ - long connecttimeout; /* in seconds, 0 means no timeout */ - long ftp_response_timeout; /* in seconds, 0 means no timeout */ - curl_off_t infilesize; /* size of file to upload, -1 means unknown */ - long low_speed_limit; /* bytes/second */ - long low_speed_time; /* number of seconds */ - curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ - curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */ - curl_off_t set_resume_from; /* continue [ftp] transfer from here */ - char *cookie; /* HTTP cookie string to send */ - struct curl_slist *headers; /* linked list of extra headers */ - struct curl_httppost *httppost; /* linked list of POST data */ - char *cert; /* certificate */ - char *cert_type; /* format for certificate (default: PEM) */ - char *key; /* private key */ - char *key_type; /* format for private key (default: PEM) */ - char *key_passwd; /* plain text private key password */ - char *cookiejar; /* dump all cookies to this file */ - bool cookiesession; /* new cookie session? */ - bool crlf; /* convert crlf on ftp upload(?) */ - char *ftp_account; /* ftp account data */ - char *ftp_alternative_to_user; /* command to send if USER/PASS fails */ - struct curl_slist *quote; /* after connection is established */ - struct curl_slist *postquote; /* after the transfer */ - struct curl_slist *prequote; /* before the transfer, after type */ - struct curl_slist *source_quote; /* 3rd party quote */ - struct curl_slist *source_prequote; /* in 3rd party transfer mode - before - the transfer on source host */ - struct curl_slist *source_postquote; /* in 3rd party transfer mode - after - the transfer on source host */ - struct curl_slist *telnet_options; /* linked list of telnet options */ - curl_TimeCond timecondition; /* kind of time/date comparison */ - time_t timevalue; /* what time to compare with */ - Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ - char *customrequest; /* HTTP/FTP request to use */ - long httpversion; /* when non-zero, a specific HTTP version requested to - be used in the library's request(s) */ - char *auth_host; /* if set, this is the allocated string to the host name - * to which to send the authorization data to, and no other - * host (which location-following otherwise could lead to) - */ - char *krb4_level; /* what security level */ - struct ssl_config_data ssl; /* user defined SSL stuff */ - - curl_proxytype proxytype; /* what kind of proxy that is in use */ - - int dns_cache_timeout; /* DNS cache timeout */ - long buffer_size; /* size of receive buffer to use */ - - char *private_data; /* Private data */ - - struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi - handle, an internal 'Curl_one_easy' - struct is created and this is a pointer - to the particular struct associated with - this SessionHandle */ - - struct curl_slist *http200aliases; /* linked list of aliases for http200 */ - - long ip_version; - - curl_off_t max_filesize; /* Maximum file size to download */ - - char *source_url; /* for 3rd party transfer */ - char *source_userpwd; /* for 3rd party transfer */ - - curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ - -/* 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 don't change during operations. */ - - bool printhost; /* printing host name in debug info */ - bool get_filetime; - bool tunnel_thru_httpproxy; - bool prefer_ascii; /* ASCII rather than binary */ - bool ftp_append; - bool ftp_list_only; - bool ftp_create_missing_dirs; - bool ftp_use_port; - bool hide_progress; - bool http_fail_on_error; - bool http_follow_location; - bool http_disable_hostname_check_before_authentication; - bool include_header; /* include received protocol headers in data output */ - bool http_set_referer; - bool http_auto_referer; /* set "correct" referer when following location: */ - bool opt_no_body; /* as set with CURLOPT_NO_BODY */ - bool set_port; - bool upload; - enum CURL_NETRC_OPTION - use_netrc; /* defined in include/curl.h */ - char *netrc_file; /* if not NULL, use this instead of trying to find - $HOME/.netrc */ - bool verbose; - bool krb4; /* kerberos4 connection requested */ - bool reuse_forbid; /* forbidden to be reused, close after use */ - bool reuse_fresh; /* do not re-use an existing connection */ - bool ftp_use_epsv; /* if EPSV is to be attempted or not */ - bool ftp_use_eprt; /* if EPRT is to be attempted or not */ - bool ftp_use_ccc; /* if CCC is to be attempted or not */ - - curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */ - curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ - bool no_signal; /* do not use any signal/alarm handler */ - bool global_dns_cache; /* subject for future removal */ - bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */ - bool ignorecl; /* ignore content length */ - bool ftp_skip_ip; /* skip the IP address the FTP server passes on to - us */ - bool connect_only; /* make connection, let application use the socket */ - long ssh_auth_types; /* allowed SSH auth types */ - char *ssh_public_key; /* the path to the public key file for - authentication */ - char *ssh_private_key; /* the path to the private key file for - authentication */ -}; - -struct Names { - struct curl_hash *hostcache; - enum { - HCACHE_NONE, /* not pointing to anything */ - HCACHE_PRIVATE, /* points to our own */ - HCACHE_GLOBAL, /* points to the (shrug) global one */ - HCACHE_MULTI, /* points to a shared one in the multi handle */ - HCACHE_SHARED /* points to a shared one in a shared object */ - } hostcachetype; -}; - -/* - * The 'connectdata' struct MUST have all the connection oriented stuff as we - * may have several simultaneous connections and connection structs in memory. - * - * The 'struct UserDefined' must only contain data that is set once to go for - * many (perhaps) independent connections. Values that are generated or - * calculated internally for the "session handle" must be defined within the - * 'struct UrlState' instead. - */ - -struct SessionHandle { - struct Names dns; - struct Curl_multi *multi; /* if non-NULL, points to the multi handle - struct to which this "belongs" */ - struct Curl_share *share; /* Share, handles global variable mutexing */ - struct HandleData reqdata; /* Request-specific data */ - struct UserDefined set; /* values set by the libcurl user */ - struct DynamicStatic change; /* possibly modified userdefined data */ - - struct CookieInfo *cookies; /* the cookies, read from files and servers */ - struct Progress progress; /* for all the progress meter data */ - struct UrlState state; /* struct for fields used for state info and - other dynamic purposes */ - struct PureInfo info; /* stats, reports and info data */ -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - iconv_t outbound_cd; /* for translating to the network encoding */ - iconv_t inbound_cd; /* for translating from the network encoding */ - iconv_t utf8_cd; /* for translating to UTF8 */ -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */ -}; - -#define LIBCURL_NAME "libcurl" - -#endif diff --git a/Utilities/cmcurl/version.c b/Utilities/cmcurl/version.c deleted file mode 100644 index 9085f7d..0000000 --- a/Utilities/cmcurl/version.c +++ /dev/null @@ -1,249 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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 http://curl.haxx.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. - * - * $Id$ - ***************************************************************************/ - -#include "setup.h" - -#include -#include - -#include -#include "urldata.h" -#include "sslgen.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - -#ifdef USE_ARES -#include -#endif - -#ifdef USE_LIBIDN -#include -#endif - -#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) -#include -#endif - -#ifdef USE_LIBSSH2 -#include -#endif - - -char *curl_version(void) -{ - static char version[200]; - char *ptr=version; - size_t len; - size_t left = sizeof(version); - strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION ); - ptr=strchr(ptr, '\0'); - left -= strlen(ptr); - - len = Curl_ssl_version(ptr, left); - left -= len; - ptr += len; - -#ifdef HAVE_LIBZ - len = snprintf(ptr, left, " zlib/%s", zlibVersion()); - left -= len; - ptr += len; -#endif -#ifdef USE_ARES - /* this function is only present in c-ares, not in the original ares */ - len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL)); - left -= len; - ptr += len; -#endif -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL)); - left -= len; - ptr += len; - } -#endif -#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) -#ifdef _LIBICONV_VERSION - len = snprintf(ptr, left, " iconv/%d.%d", - _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); -#else - /* version unknown */ - len = snprintf(ptr, left, " iconv"); -#endif /* _LIBICONV_VERSION */ - left -= len; - ptr += len; -#endif -#ifdef USE_LIBSSH2 - len = snprintf(ptr, left, " libssh2/%s", LIBSSH2_VERSION); - left -= len; - ptr += len; -#endif - - return version; -} - -/* data for curl_version_info */ - -static const char * const protocols[] = { -#ifndef CURL_DISABLE_TFTP - "tftp", -#endif -#ifndef CURL_DISABLE_FTP - "ftp", -#endif -#ifndef CURL_DISABLE_TELNET - "telnet", -#endif -#ifndef CURL_DISABLE_DICT - "dict", -#endif -#ifndef CURL_DISABLE_LDAP - "ldap", -#endif -#ifndef CURL_DISABLE_HTTP - "http", -#endif -#ifndef CURL_DISABLE_FILE - "file", -#endif - -#ifdef USE_SSL -#ifndef CURL_DISABLE_HTTP - "https", -#endif -#ifndef CURL_DISABLE_FTP - "ftps", -#endif -#endif - -#ifdef USE_LIBSSH2 - "scp", - "sftp", -#endif - - NULL -}; - -static curl_version_info_data version_info = { - CURLVERSION_NOW, - LIBCURL_VERSION, - LIBCURL_VERSION_NUM, - OS, /* as found by configure or set by hand at build-time */ - 0 /* features is 0 by default */ -#ifdef ENABLE_IPV6 - | CURL_VERSION_IPV6 -#endif -#ifdef HAVE_KRB4 - | CURL_VERSION_KERBEROS4 -#endif -#ifdef USE_SSL - | CURL_VERSION_SSL -#endif -#ifdef USE_NTLM - | CURL_VERSION_NTLM -#endif -#ifdef USE_WINDOWS_SSPI - | CURL_VERSION_SSPI -#endif -#ifdef HAVE_LIBZ - | CURL_VERSION_LIBZ -#endif -#ifdef HAVE_GSSAPI - | CURL_VERSION_GSSNEGOTIATE -#endif -#ifdef CURLDEBUG - | CURL_VERSION_DEBUG -#endif -#ifdef USE_ARES - | CURL_VERSION_ASYNCHDNS -#endif -#ifdef HAVE_SPNEGO - | CURL_VERSION_SPNEGO -#endif -#if defined(ENABLE_64BIT) && (SIZEOF_CURL_OFF_T > 4) - | CURL_VERSION_LARGEFILE -#endif -#if defined(CURL_DOES_CONVERSIONS) - | CURL_VERSION_CONV -#endif - , - NULL, /* ssl_version */ - 0, /* ssl_version_num, this is kept at zero */ - NULL, /* zlib_version */ - protocols, - NULL, /* c-ares version */ - 0, /* c-ares version numerical */ - NULL, /* libidn version */ - 0, /* iconv version */ - NULL, /* ssh lib version */ -}; - -curl_version_info_data *curl_version_info(CURLversion stamp) -{ -#ifdef USE_LIBSSH2 - static char ssh_buffer[80]; -#endif - -#ifdef USE_SSL - static char ssl_buffer[80]; - Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); - version_info.ssl_version = ssl_buffer; -#endif - -#ifdef HAVE_LIBZ - version_info.libz_version = zlibVersion(); - /* libz left NULL if non-existing */ -#endif -#ifdef USE_ARES - { - int aresnum; - version_info.ares = ares_version(&aresnum); - version_info.ares_num = aresnum; - } -#endif -#ifdef USE_LIBIDN - /* This returns a version string if we use the given version or later, - otherwise it returns NULL */ - version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION); - if(version_info.libidn) - version_info.features |= CURL_VERSION_IDN; -#endif - -#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) -#ifdef _LIBICONV_VERSION - version_info.iconv_ver_num = _LIBICONV_VERSION; -#else - /* version unknown */ - version_info.iconv_ver_num = -1; -#endif /* _LIBICONV_VERSION */ -#endif - -#ifdef USE_LIBSSH2 - snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION); - version_info.libssh_version = ssh_buffer; -#endif - - (void)stamp; /* avoid compiler warnings, we don't use this */ - - return &version_info; -} -- cgit v0.12