Compare commits
91 Commits
curl-7_14_
...
curl-7_15_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
96cec4dfd7 | ||
![]() |
943aea6267 | ||
![]() |
b433e4a1e7 | ||
![]() |
20f1966c0e | ||
![]() |
ab1f5c3edd | ||
![]() |
b2be6799f2 | ||
![]() |
ea2618fc6f | ||
![]() |
62fdf8eaed | ||
![]() |
d3569a3572 | ||
![]() |
89df76e449 | ||
![]() |
e5b2f33b4f | ||
![]() |
934d312f50 | ||
![]() |
68917eb517 | ||
![]() |
3beb2f6b5d | ||
![]() |
b29017f15b | ||
![]() |
db83a0ebbc | ||
![]() |
6d9fddb95d | ||
![]() |
4284190cc4 | ||
![]() |
5e4cbd2d24 | ||
![]() |
06c3bec65d | ||
![]() |
e8c3bb45ba | ||
![]() |
4ec55a964d | ||
![]() |
b9420864c0 | ||
![]() |
bf6588b6a7 | ||
![]() |
e43217e664 | ||
![]() |
e19ee2d102 | ||
![]() |
b4c53e2cfd | ||
![]() |
a2902de67c | ||
![]() |
da192f7955 | ||
![]() |
a2210d23c3 | ||
![]() |
bd5a622400 | ||
![]() |
b9494cb0d6 | ||
![]() |
0f73af4470 | ||
![]() |
45e26b5c02 | ||
![]() |
6af5ea38ce | ||
![]() |
b6f0aa4394 | ||
![]() |
774dab58f6 | ||
![]() |
e3bdb98f7a | ||
![]() |
58d628c9f8 | ||
![]() |
1e69394545 | ||
![]() |
1cf798ad14 | ||
![]() |
da3992d2e9 | ||
![]() |
48908e4633 | ||
![]() |
f5ae149338 | ||
![]() |
3fe5311967 | ||
![]() |
6a48639c68 | ||
![]() |
e7093b3ca8 | ||
![]() |
d0a4104c0c | ||
![]() |
90559bed53 | ||
![]() |
973a18cf03 | ||
![]() |
3c666ce57a | ||
![]() |
a1287ec64f | ||
![]() |
5fbfa1bfa8 | ||
![]() |
da3ecc91f8 | ||
![]() |
09c8f558f7 | ||
![]() |
528a149def | ||
![]() |
29e36afb6b | ||
![]() |
0e39543d35 | ||
![]() |
0de20d8ee6 | ||
![]() |
cd5de5c0e5 | ||
![]() |
bd5afc26bd | ||
![]() |
9542dfdcdc | ||
![]() |
97a6d7b1a8 | ||
![]() |
209b9d4374 | ||
![]() |
0b8ccd0ae7 | ||
![]() |
0b7f5ad508 | ||
![]() |
8a38805e82 | ||
![]() |
836d88a4b8 | ||
![]() |
d5268ed511 | ||
![]() |
0e7d93858d | ||
![]() |
2164d760b7 | ||
![]() |
b9c8de598b | ||
![]() |
9889a811db | ||
![]() |
9e38d882b9 | ||
![]() |
e8635044b5 | ||
![]() |
56dea0ac9a | ||
![]() |
e8b77477c7 | ||
![]() |
64298e528d | ||
![]() |
4f1465e7c7 | ||
![]() |
6120041b69 | ||
![]() |
8c1213627d | ||
![]() |
3e6ae6eeb8 | ||
![]() |
291e9aeabd | ||
![]() |
a3d776187a | ||
![]() |
e55f502e2f | ||
![]() |
e369270f88 | ||
![]() |
7e845e7cfd | ||
![]() |
56d9624b56 | ||
![]() |
911d135deb | ||
![]() |
8107b90678 | ||
![]() |
7722452b98 |
134
CHANGES
134
CHANGES
@@ -7,6 +7,100 @@
|
||||
Changelog
|
||||
|
||||
|
||||
|
||||
Version 7.15.0 (13 October 2005)
|
||||
|
||||
Daniel (12 October 2005)
|
||||
- Michael Sutton of iDEFENSE reported and I fixed a securitfy flaw in the NTLM
|
||||
code that would overflow a buffer if given a too long user name or domain
|
||||
name. This would happen if you enable NTLM authentication and either
|
||||
|
||||
A - pass in a user name and domain name to libcurl that together are longer
|
||||
than 192 bytes
|
||||
|
||||
B - allow (lib)curl to follow HTTP "redirects" (Location: and the
|
||||
appropriate HTTP 30x response code) and the new URL contains a URL with
|
||||
a user name and domain name that together are longer than 192 bytes
|
||||
|
||||
See http://curl.haxx.se/docs/security.html for further details and updates
|
||||
|
||||
Daniel (5 October 2005)
|
||||
- Darryl House reported a problem with using -z to download files from FTP.
|
||||
It turned out that if the given time stamp was exact the same as the remote
|
||||
time stamp, the file would still wrongly be downloaded. Added test case 272
|
||||
to verify.
|
||||
|
||||
Daniel (4 October 2005)
|
||||
- Domenico Andreoli fixed a man page malformat and removed odd (0xa0) bytes
|
||||
from the configure script.
|
||||
|
||||
- Michael Wallner reported that the date parser had wrong offset stored for
|
||||
the MEST and CEST time zones.
|
||||
|
||||
Daniel (27 September 2005)
|
||||
- David Yan filed bug #1299181 (http://curl.haxx.se/bug/view.cgi?id=1299181)
|
||||
that identified a silly problem with Content-Range: headers with the 'bytes'
|
||||
keyword written in a different case than all lowercase! It would cause a
|
||||
segfault!
|
||||
|
||||
- TJ Saunders of the proftpd project identified and pointed out problems with
|
||||
the modified FTPS negotiation change of August 19 2005. Thus, we revert the
|
||||
change back to pre-7.14.1 status.
|
||||
|
||||
Daniel (21 September 2005)
|
||||
- Fixed "cut off" sentence in the libcurl-tutorial man page:
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=329305
|
||||
|
||||
- Clarified in the curl_easy_setopt man page what the default
|
||||
CURLOPT_WRITEFUNCTION and CURLOPT_WRITEDATA mean:
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=329311
|
||||
|
||||
- Clarified in the curl_easy_setopt man page that CURLOPT_ERRORBUFFER
|
||||
sometimes doesn't fill in the buffer even though it is supposed to:
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=329313
|
||||
|
||||
- When CURLE_URL_MALFORMAT is returned due to a missing URL, it now has an
|
||||
error string set.
|
||||
|
||||
Daniel (19 September 2005)
|
||||
- Dmitry Bartsevich made the SSPI support work on Windows 9x as well.
|
||||
|
||||
Daniel (15 September 2005)
|
||||
- Added a TFTP server to the test suite and made the test suite capable of
|
||||
using it.
|
||||
|
||||
Daniel (7 September 2005)
|
||||
- Ben Madsen's detailed reports that funnily enough only occurred with certain
|
||||
glibc versions turned out to be curl using an already closed file handle
|
||||
during certain conditions (like when saving FTP server "headers").
|
||||
|
||||
- Scott Davis helped me track down a problem in the test HTTP server that made
|
||||
test case 56 wrongly fail at times. It turned out it was due to the server
|
||||
finding the end of a chunked-encoded POST too early.
|
||||
|
||||
Daniel (6 September 2005)
|
||||
- Now curl warns if an unknown variable is used in the -w/--writeout argument.
|
||||
|
||||
Daniel (4 September 2005)
|
||||
- I applied Nicolas Fran<61>ois' man page patch he posted to the Debian bug
|
||||
tracker. It corrected two lines that started with apostrophes, which isn't
|
||||
legal nroff format. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=326511
|
||||
|
||||
- Added --ftp-skip-pasv-ip to the command line tool, that sets the new
|
||||
CURLOPT_FTP_SKIP_PASV_IP option. It makes libcurl re-use the control
|
||||
connection's IP address when setting up the data connection instead of
|
||||
extractting the IP address from the PASV response. It has turned out this
|
||||
feature is frequently needed by people to circumvent silly servers and silly
|
||||
firewalls, especially when FTPS is used and the PASV command-response is
|
||||
sent encrtyped.
|
||||
|
||||
Sponsored by CU*Answers
|
||||
|
||||
Daniel (1 September 2005)
|
||||
- John Kelly added TFTP support to libcurl. A bunch of new error codes was
|
||||
added. TODO: add them to docs. add TFTP server to test suite. add TFTP to
|
||||
list of protocols whereever those are mentioned.
|
||||
|
||||
Version 7.14.1 (1 September 2005)
|
||||
|
||||
Daniel (29 August 2005)
|
||||
@@ -93,10 +187,11 @@ Daniel (9 August 2005)
|
||||
zone names thus limiting the effect of this bug.
|
||||
|
||||
Daniel (8 August 2005)
|
||||
- Jon Grubbs filed bug report #1249962 which identified a problem with NTLM on
|
||||
a HTTP proxy if an FTP URL was given. libcurl now properly switches to pure
|
||||
HTTP internally when an HTTP proxy is used, even for FTP URLs. The problem
|
||||
would also occur with other multi-pass auth methods.
|
||||
- Jon Grubbs filed bug report #1249962
|
||||
(http://curl.haxx.se/bug/view.cgi?id=1249962) which identified a problem
|
||||
with NTLM on a HTTP proxy if an FTP URL was given. libcurl now properly
|
||||
switches to pure HTTP internally when an HTTP proxy is used, even for FTP
|
||||
URLs. The problem would also occur with other multi-pass auth methods.
|
||||
|
||||
Daniel (7 August 2005)
|
||||
- When curl is built with GnuTLS, curl-config didn't include "SSL" when
|
||||
@@ -125,11 +220,11 @@ Daniel (12 July 2005)
|
||||
contains a flawed chunked encoding stream that still works the same.
|
||||
|
||||
Daniel (5 July 2005)
|
||||
- Gisle Vanem came up with a nice little work-around for bug #1230118. It
|
||||
seems the Windows (MSVC) libc time functions may return data one hour off if
|
||||
TZ is not set and automatic DST adjustment is enabled. This made
|
||||
curl_getdate() return wrong value, and it also concerned internal cookie
|
||||
expirations etc.
|
||||
- Gisle Vanem came up with a nice little work-around for bug #1230118
|
||||
(http://curl.haxx.se/bug/view.cgi?id=1230118). It seems the Windows (MSVC)
|
||||
libc time functions may return data one hour off if TZ is not set and
|
||||
automatic DST adjustment is enabled. This made curl_getdate() return wrong
|
||||
value, and it also concerned internal cookie expirations etc.
|
||||
|
||||
Daniel (4 July 2005)
|
||||
- Andrew Bushnell provided enough info for me to tell that we badly needed to
|
||||
@@ -165,8 +260,9 @@ Daniel (22 June 2005)
|
||||
- David Shaw updated libcurl.m4
|
||||
|
||||
Daniel (14 June 2005)
|
||||
- Gisle Vanem fixed a potential thread handle leak. Bug report #1216500.
|
||||
Comment in http://curl.haxx.se/mail/lib-2005-06/0059.html
|
||||
- Gisle Vanem fixed a potential thread handle leak. Bug report #1216500
|
||||
(http://curl.haxx.se/bug/view.cgi?id=1216500). Comment in
|
||||
http://curl.haxx.se/mail/lib-2005-06/0059.html
|
||||
|
||||
Daniel (13 June 2005)
|
||||
- Made buildconf run libtoolize in the ares dir too (inspired by Tupone's
|
||||
@@ -202,7 +298,7 @@ Daniel (3 June 2005)
|
||||
Daniel (1 June 2005)
|
||||
- The configure check for c-ares now adds the cares lib before the other libs,
|
||||
to make it build fine with mingw. Inspired by Tupone Alfredo's bug report
|
||||
(and patch) #1212940
|
||||
and patch: http://curl.haxx.se/bug/view.cgi?id=1212940
|
||||
|
||||
Daniel (31 May 2005)
|
||||
- Todd Kulesza reported a flaw in the proxy option, since a numerical IPv6
|
||||
@@ -214,7 +310,7 @@ Daniel (30 May 2005)
|
||||
- Eric Cooper reported about a problem with HTTP servers that responds with
|
||||
binary zeroes within the headers. They confused libcurl to do wrong so the
|
||||
downloaded headers become incomplete. The fix is now verified with test case
|
||||
262.
|
||||
262. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=310948
|
||||
|
||||
Daniel (25 May 2005)
|
||||
- Fixed problems with the test suite, and in particular the FTP test cases
|
||||
@@ -236,9 +332,10 @@ Daniel (20 May 2005)
|
||||
docs.
|
||||
|
||||
Daniel (18 May 2005)
|
||||
- John McGowan identified a problem in bug report #1204435 with malformed URLs
|
||||
like "http://somehost?data" as it added a slash too much in the request
|
||||
("GET /?data/"...). Added test case 260 to verify.
|
||||
- John McGowan identified a problem in bug report #1204435
|
||||
(http://curl.haxx.se/bug/view.cgi?id=1204435) with malformed URLs like
|
||||
"http://somehost?data" as it added a slash too much in the request ("GET
|
||||
/?data/"...). Added test case 260 to verify.
|
||||
|
||||
- The configure check for strerror_r() failed to detect the proper API at
|
||||
times, like on HP-UX 10.20. Then lib/strerror.c badly assumed the glibc
|
||||
@@ -261,8 +358,9 @@ Daniel (12 May 2005)
|
||||
- When doing a second request (after a disconnect) using the same easy handle,
|
||||
over a proxy that uses NTLM authentication, libcurl failed to use NTLM again
|
||||
properly (the auth method was accidentally reset to the same as had been set
|
||||
for host auth, which defaults to Basic). Bug report #1200661 identified the
|
||||
the problem and the fix.
|
||||
for host auth, which defaults to Basic). Bug report #1200661
|
||||
(http://curl.haxx.se/bug/view.cgi?id=1200661) identified the the problem and
|
||||
the fix.
|
||||
|
||||
- If -z/--time-cond is used with an invalid date syntax, this is no longer
|
||||
silently discarded. Instead a proper warning message is diplayed that
|
||||
|
@@ -1,74 +1,46 @@
|
||||
Curl and libcurl 7.14.1
|
||||
Curl and libcurl 7.15.0
|
||||
|
||||
Public curl release number: 89
|
||||
Releases counted from the very beginning: 116
|
||||
Available command line options: 108
|
||||
Available curl_easy_setopt() options: 123
|
||||
Public curl release number: 90
|
||||
Releases counted from the very beginning: 117
|
||||
Available command line options: 109
|
||||
Available curl_easy_setopt() options: 124
|
||||
Number of public functions in libcurl: 46
|
||||
Amount of public web site mirrors: 25
|
||||
Number of known libcurl bindings: 31
|
||||
Number of contributors: 447
|
||||
Amount of public web site mirrors: 24
|
||||
Number of known libcurl bindings: 32
|
||||
Number of contributors: 451
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o GNU GSS support
|
||||
o --ignore-content-length and CURLOPT_IGNORE_CONTENT_LENGTH added
|
||||
o negotiates data connection SSL earlier when doing FTPS with PASV
|
||||
o CURLOPT_COOKIELIST and CURLINFO_COOKIELIST
|
||||
o trailer support for chunked encoded data streams
|
||||
o -x/CURL_PROXY strings may now contain user+password
|
||||
o --trace-time now outputs the full microsecond, all 6 digits
|
||||
o --ftp-skip-pasv-ip / CURLOPT_FTP_SKIP_PASV_IP (sponsored by CU*Answers)
|
||||
o TFTP support added
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o MSVC build problem with the DSP file
|
||||
o windows threaded resolver access violation with multi interface
|
||||
o test suite works with valgrind 3
|
||||
o CA cert verification with GnuTLS builds
|
||||
o handles expiry times in cookie files that go beyond 32 bits in size
|
||||
o several client problems with files, such as doing -d @file when the file
|
||||
isn't readable now gets a warning displayed
|
||||
o write callback abort didn't always "take"
|
||||
o the curl -z "bad syntax" warning is now hidden when -s is used
|
||||
o curl -d @nonexisting no longer makes a GET
|
||||
o minor debug callback data size
|
||||
o date parsing of dates including daylight savings time zone names
|
||||
o using NTLM over proxy with an FTP URL
|
||||
o curl-config --features now displays SSL when built with GnuTLS too
|
||||
o CURLOPT_HTTPGET, CURLOPT_POST and CURLOPT_HTTPPOST reset CURLOPT_NOBODY
|
||||
o builds fine on AmigaOS again
|
||||
o corrected date parsing on Windows with auto-DST-adjust enabled
|
||||
o treats CONNECT 407 responses with bodies better during Digest/NTLM auth
|
||||
o improved strerror_r() API guessing when cross-compiling
|
||||
o debug builds work on Tru64
|
||||
o improved libcurl.m4
|
||||
o possible memory leak in windows name resolves
|
||||
o c-ares enabled build with mingw
|
||||
o proxy host set with numerical IPv6 address
|
||||
o better treatment of binary zeroes in HTTP response headers
|
||||
o fixed the notorious FTP server failure in the test suite
|
||||
o better checking of text output in the test suite on windows
|
||||
o FTP servers' TYPE command response check made less strict
|
||||
o URL-without-slash as in http://somehost?data
|
||||
o strerror_r() configure check for HP-UX 10.20 (and others)
|
||||
o time parse work-around on HP-UX 10.20 since its gmtime_r() is broken
|
||||
o user+domain name buffer overflow in the NTLM code (security flaw)
|
||||
o -z over FTP now considers equal timestamps "not modified since"
|
||||
o Weird characters removed from the configure script
|
||||
o Fixed time zone offsets for MEST and CEST for the time parser
|
||||
o HTTP Content-Range header parser crash
|
||||
o FTPS negotiation timeouts/errors
|
||||
o SSPI works even for Windows 9x
|
||||
o crash in --dump-header on FTP
|
||||
o test 56 runs better
|
||||
|
||||
Other curl-related news since the previous public release:
|
||||
|
||||
o cURLpp 0.5.2 was released at http://rrette.com/curlpp.html
|
||||
o Rexx/CURL 1.3 was released at http://rexxcurl.sf.net/
|
||||
o http://curl.miscellaneousmirror.org is a new German curl mirror
|
||||
o LuaCURL by Alexander Marinov at http://luacurl.luaforge.net/
|
||||
o http://curl.hostingzero.com/ is a new US curl mirror
|
||||
o ocurl 0.2.1 was released at http://sourceforge.net/projects/ocurl
|
||||
o http://curl.freemirror.de/ is a new German mirror
|
||||
o All curl relatd mailing list information and subscribers on cool.haxx.se
|
||||
were lost due to a malicious user exploiting a security hole on the
|
||||
server. Attempts have been made to put back susbcribers on the lists, but
|
||||
many have been lost: http://curl.haxx.se/mail/lost.html
|
||||
o New S-Lang binding: http://curl.haxx.se/libcurl/slang/
|
||||
o TclCurl 0.14.1: http://personal1.iddeo.es/andresgarci/tclcurl/english/
|
||||
o pycurl 7.14.1: http://pycurl.sf.net/
|
||||
|
||||
This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
John McGowan, Georg Wicherski, Andres Garcia, Eric Cooper, Todd Kulesza,
|
||||
Tupone Alfredo, Gisle Vanem, David Shaw, Andrew Bushnell, Dan Fandrich,
|
||||
Adrian Schuur, Diego Casorran, Peteris Krumins, Jon Grubbs, Christopher
|
||||
R. Palmer, Mario Schroeder, Richard Clayton, James Bursa, Jeff Pohlmeyer,
|
||||
Norbert Novotny, Toby Peterson, Simon Josefsson, Igor Polyakov, Kevin Lussier
|
||||
o John Kelly, Nicolas Fran<61>ois, Scott Davis, Ben Madsen, Dmitry Bartsevich,
|
||||
David Yan, Michael Wallner, Domenico Andreoli, Darryl House
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
@@ -1,12 +1,7 @@
|
||||
Issues not sorted in any particular order.
|
||||
|
||||
To get fixed in 7.14.1 (planned release: August 2005)
|
||||
To get fixed in 7.15.0 (planned release: November 2005)
|
||||
======================
|
||||
|
||||
To get fixed in 7.14.2 (planned release: October 2005)
|
||||
======================
|
||||
|
||||
60 - CONNECT 407 responses that kills the connection
|
||||
60 - CONNECT 407 responses that kills the connection (not very likely though)
|
||||
|
||||
63 -
|
||||
|
||||
|
12
ares/CHANGES
12
ares/CHANGES
@@ -1,5 +1,17 @@
|
||||
Changelog for the c-ares project
|
||||
|
||||
* September 18
|
||||
|
||||
- Added constants that will be used by ares_getaddrinfo
|
||||
|
||||
- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it is
|
||||
available to ensure it works properly in a threaded environment.
|
||||
|
||||
* September 10
|
||||
|
||||
- configure fix for detecting a member in the sockaddr_in6 struct which failed
|
||||
on ipv6-enabled HP-UX 11.00
|
||||
|
||||
Version 1.3.0 (August 29, 2004)
|
||||
|
||||
* August 21
|
||||
|
@@ -242,26 +242,6 @@ AC_DEFUN([CARES_CHECK_STRUCT], [
|
||||
fi
|
||||
])
|
||||
|
||||
dnl This macro determins if the specified struct contains a specific member.
|
||||
dnl Syntax:
|
||||
dnl CARES_CHECK_STRUCT_MEMBER(headers, struct name, member name, if found, [if not found])
|
||||
|
||||
AC_DEFUN([CARES_CHECK_STRUCT_MEMBER], [
|
||||
AC_MSG_CHECKING([if struct $2 has member $3])
|
||||
AC_TRY_COMPILE([$1],
|
||||
[
|
||||
struct $2 struct_instance;
|
||||
struct_instance.$3 = 0;
|
||||
], ac_struct="yes", ac_found="no")
|
||||
if test "$ac_struct" = "yes" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
$4
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
$5
|
||||
fi
|
||||
])
|
||||
|
||||
dnl This macro determines if the specified constant exists in the specified file
|
||||
dnl Syntax:
|
||||
dnl CARES_CHECK_CONSTANT(headers, constant name, if found, [if not found])
|
||||
@@ -289,3 +269,50 @@ AC_DEFUN([CARES_CHECK_CONSTANT], [
|
||||
])
|
||||
|
||||
|
||||
dnl This macro determines how many parameters getservbyport_r takes
|
||||
AC_DEFUN([CARES_CHECK_GETSERVBYPORT_R], [
|
||||
AC_MSG_CHECKING([how many arguments getservbyport_r takes])
|
||||
AC_TRY_COMPILE(
|
||||
[#include <netdb.h>],
|
||||
[
|
||||
int p1, p5;
|
||||
char *p2, p4[4096];
|
||||
struct servent *p3, *p6;
|
||||
getservbyport_r(p1, p2, p3, p4, p5, &p6);
|
||||
], ac_func_getservbyport_r=6,
|
||||
[AC_TRY_COMPILE(
|
||||
[#include <netdb.h>],
|
||||
[
|
||||
int p1, p5;
|
||||
char *p2, p4[4096];
|
||||
struct servent *p3;
|
||||
getservbyport_r(p1, p2, p3, p4, p5);
|
||||
], ac_func_getservbyport_r=5,
|
||||
[AC_TRY_COMPILE(
|
||||
[#include <netdb.h>],
|
||||
[
|
||||
int p1;
|
||||
char *p2;
|
||||
struct servent *p3;
|
||||
struct servent_data p4;
|
||||
getservbyport_r(p1, p2, p3, &p4);
|
||||
], ac_func_getservbyport_r=4, ac_func_getservbyport_r=0
|
||||
)]
|
||||
)]
|
||||
)
|
||||
if test $ac_func_getservbyport_r != "0" ; then
|
||||
AC_MSG_RESULT($ac_func_getservbyport_r)
|
||||
AC_DEFINE(HAVE_GETSERVBYPORT_R, 1, [Specifies whether getservbyport_r is present])
|
||||
AC_DEFINE_UNQUOTED(GETSERVBYPORT_R_ARGS, $ac_func_getservbyport_r, [Specifies the number of arguments to
|
||||
getservbyport_r])
|
||||
if test $ac_func_getservbyport_r = "4" ; then
|
||||
AC_DEFINE(GETSERVBYPORT_R_BUFSIZE, sizeof(struct servent_data), [Specifies the size of the buffer to pass to
|
||||
getservbyport_r])
|
||||
else
|
||||
AC_DEFINE(GETSERVBYPORT_R_BUFSIZE, 4096, [Specifies the size of the buffer to pass to getservbyport_r])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([not found])
|
||||
fi
|
||||
])
|
||||
|
||||
|
28
ares/ares.h
28
ares/ares.h
@@ -69,6 +69,10 @@ extern "C" {
|
||||
/* ares_getnameinfo error codes */
|
||||
#define ARES_EBADFLAGS 18
|
||||
|
||||
/* ares_getaddrinfo error codes */
|
||||
#define ARES_ENONAME 19
|
||||
#define ARES_EBADHINTS 20
|
||||
|
||||
/* Flag values */
|
||||
#define ARES_FLAG_USEVC (1 << 0)
|
||||
#define ARES_FLAG_PRIMARY (1 << 1)
|
||||
@@ -104,9 +108,27 @@ extern "C" {
|
||||
#define ARES_NI_LOOKUPHOST (1 << 8)
|
||||
#define ARES_NI_LOOKUPSERVICE (1 << 9)
|
||||
/* Reserved for future use */
|
||||
#define ARES_NI_IDN (1 << 10)
|
||||
#define ARES_NI_ALLOW_UNASSIGNED (1 << 11)
|
||||
#define ARES_NI_USE_STD3_ASCII_RULES (1 << 12)
|
||||
#define ARES_NI_IDN (1 << 10)
|
||||
#define ARES_NI_IDN_ALLOW_UNASSIGNED (1 << 11)
|
||||
#define ARES_NI_IDN_USE_STD3_ASCII_RULES (1 << 12)
|
||||
|
||||
/* Addrinfo flag values */
|
||||
#define ARES_AI_CANONNAME (1 << 0)
|
||||
#define ARES_AI_NUMERICHOST (1 << 1)
|
||||
#define ARES_AI_PASSIVE (1 << 2)
|
||||
#define ARES_AI_NUMERICSERV (1 << 3)
|
||||
#define ARES_AI_V4MAPPED (1 << 4)
|
||||
#define ARES_AI_ALL (1 << 5)
|
||||
#define ARES_AI_ADDRCONFIG (1 << 6)
|
||||
/* Reserved for future use */
|
||||
#define ARES_AI_IDN (1 << 10)
|
||||
#define ARES_AI_IDN_ALLOW_UNASSIGNED (1 << 11)
|
||||
#define ARES_AI_IDN_USE_STD3_ASCII_RULES (1 << 12)
|
||||
#define ARES_AI_CANONIDN (1 << 13)
|
||||
|
||||
#define ARES_AI_MASK (ARES_AI_CANONNAME|ARES_AI_NUMERICHOST|ARES_AI_PASSIVE| \
|
||||
ARES_AI_NUMERICSERV|ARES_AI_V4MAPPED|ARES_AI_ALL| \
|
||||
ARES_AI_ADDRCONFIG)
|
||||
|
||||
struct ares_options {
|
||||
int flags;
|
||||
|
@@ -194,9 +194,11 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
|
||||
if (niquery->flags & ARES_NI_LOOKUPSERVICE)
|
||||
{
|
||||
if (niquery->family == AF_INET)
|
||||
service = lookup_service(niquery->addr.addr4.sin_port, niquery->flags, srvbuf);
|
||||
service = lookup_service(niquery->addr.addr4.sin_port,
|
||||
niquery->flags, srvbuf);
|
||||
else
|
||||
service = lookup_service(niquery->addr.addr6.sin6_port, niquery->flags, srvbuf);
|
||||
service = lookup_service(niquery->addr.addr6.sin6_port,
|
||||
niquery->flags, srvbuf);
|
||||
}
|
||||
/* NOFQDN means we have to strip off the domain name portion.
|
||||
We do this by determining our own domain name, then searching the string
|
||||
@@ -234,9 +236,11 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
|
||||
if (niquery->flags & ARES_NI_LOOKUPSERVICE)
|
||||
{
|
||||
if (niquery->family == AF_INET)
|
||||
service = lookup_service(niquery->addr.addr4.sin_port, niquery->flags, srvbuf);
|
||||
service = lookup_service(niquery->addr.addr4.sin_port,
|
||||
niquery->flags, srvbuf);
|
||||
else
|
||||
service = lookup_service(niquery->addr.addr6.sin6_port, niquery->flags, srvbuf);
|
||||
service = lookup_service(niquery->addr.addr6.sin6_port,
|
||||
niquery->flags, srvbuf);
|
||||
}
|
||||
niquery->callback(niquery->arg, ARES_SUCCESS, ipbuf, service);
|
||||
return;
|
||||
@@ -245,7 +249,8 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
|
||||
free(niquery);
|
||||
}
|
||||
|
||||
static char *lookup_service(unsigned short port, int flags, char *buf)
|
||||
static char *lookup_service(unsigned short port, int flags,
|
||||
char *buf) /* 33 bytes buffer */
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
@@ -256,7 +261,17 @@ static char *lookup_service(unsigned short port, int flags, char *buf)
|
||||
{
|
||||
struct servent *se;
|
||||
const char *proto;
|
||||
|
||||
#if GETSERVBYPORT_R_ARGS == 6
|
||||
struct servent ret;
|
||||
char buf[4096];
|
||||
int len = 4096;
|
||||
#elif GETSERVBYPORT_R_ARGS == 5
|
||||
char buf[4096];
|
||||
int len = 4096;
|
||||
#elif GETSERVBYPORT_R_ARGS == 4
|
||||
struct servent ret;
|
||||
struct servent_data sed;
|
||||
#endif
|
||||
if (flags & ARES_NI_UDP)
|
||||
proto = "udp";
|
||||
else if (flags & ARES_NI_SCTP)
|
||||
@@ -265,9 +280,34 @@ static char *lookup_service(unsigned short port, int flags, char *buf)
|
||||
proto = "dccp";
|
||||
else
|
||||
proto = "tcp";
|
||||
#ifdef HAVE_GETSERVBYPORT_R
|
||||
#if GETSERVBYPORT_R_ARGS == 6
|
||||
se = &ret;
|
||||
if (getservbyport_r(port, proto, se, buf, len, &ret))
|
||||
se = NULL;
|
||||
#elif GETSERVBYPORT_R_ARGS == 5
|
||||
se = getservbyport_r(port, proto, se, buf, len);
|
||||
#elif GETSERVBYPORT_R_ARGS == 4
|
||||
se = &ret;
|
||||
if (getservbyport_r(port, proto, se, &sed) == -1)
|
||||
se = NULL;
|
||||
#else
|
||||
/* Lets just hope the OS uses TLS! */
|
||||
se = getservbyport(port, proto);
|
||||
if (se && se->s_name)
|
||||
strcpy(buf, se->s_name);
|
||||
#endif
|
||||
#else
|
||||
/* Lets just hope the OS uses TLS! */
|
||||
se = getservbyport(port, proto);
|
||||
#endif
|
||||
if (se && se->s_name) {
|
||||
size_t len = strlen(se->s_name);
|
||||
if(len < 33) {
|
||||
strcpy(buf, se->s_name);
|
||||
}
|
||||
else
|
||||
/* too big name to fit the buffer */
|
||||
buf[0]=0;
|
||||
}
|
||||
else
|
||||
sprintf(buf, "%u", ntohs(port));
|
||||
}
|
||||
@@ -277,14 +317,16 @@ static char *lookup_service(unsigned short port, int flags, char *buf)
|
||||
}
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
static char *append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags, char *buf)
|
||||
static char *append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags,
|
||||
char *buf)
|
||||
{
|
||||
char tmpbuf[IF_NAMESIZE + 1];
|
||||
|
||||
tmpbuf[0] = '%';
|
||||
#ifdef HAVE_IF_INDEXTONAME
|
||||
if ((flags & ARES_NI_NUMERICSCOPE) || (!IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)
|
||||
&& !IN6_IS_ADDR_MC_LINKLOCAL(&addr6->sin6_addr)))
|
||||
if ((flags & ARES_NI_NUMERICSCOPE) ||
|
||||
(!IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)
|
||||
&& !IN6_IS_ADDR_MC_LINKLOCAL(&addr6->sin6_addr)))
|
||||
{
|
||||
sprintf(&tmpbuf[1], "%u", addr6->sin6_scope_id);
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@ AC_CHECK_HEADERS(
|
||||
sys/select.h \
|
||||
sys/socket.h \
|
||||
sys/ioctl.h \
|
||||
netdb.h \
|
||||
winsock.h \
|
||||
netinet/in.h \
|
||||
net/if.h \
|
||||
@@ -175,8 +176,10 @@ CARES_CHECK_STRUCT(
|
||||
[Define to 1 if you have struct sockaddr_in6.]) ac_have_sockaddr_in6=yes
|
||||
)
|
||||
|
||||
if test "$ac_have_sockaddr_in6" = "yes" ; then
|
||||
CARES_CHECK_STRUCT_MEMBER(
|
||||
AC_CHECK_MEMBER(struct sockaddr_in6.sin6_scope_id,
|
||||
AC_DEFINE_UNQUOTED(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID,1,
|
||||
[Define to 1 if your struct sockaddr_in6 has sin6_scope_id.])
|
||||
, ,
|
||||
[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
@@ -187,14 +190,12 @@ CARES_CHECK_STRUCT_MEMBER(
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
], [sockaddr_in6], [sin6_scope_id],
|
||||
AC_DEFINE_UNQUOTED(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID,1,
|
||||
[Define to 1 if your struct sockaddr_in6 has sin6_scope_id.])
|
||||
)
|
||||
fi
|
||||
])
|
||||
|
||||
dnl check for the addrinfo structure
|
||||
CARES_CHECK_STRUCT(
|
||||
AC_CHECK_MEMBER(struct addrinfo.ai_flags,
|
||||
AC_DEFINE_UNQUOTED(HAVE_STRUCT_ADDRINFO,1,
|
||||
[Define to 1 if you have struct addrinfo.]),,
|
||||
[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
@@ -205,9 +206,13 @@ CARES_CHECK_STRUCT(
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
], [addrinfo],
|
||||
AC_DEFINE_UNQUOTED(HAVE_STRUCT_ADDRINFO,1,
|
||||
[Define to 1 if you have struct addrinfo.])
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
]
|
||||
)
|
||||
|
||||
dnl check for inet_pton
|
||||
@@ -346,6 +351,9 @@ AC_CHECK_SIZEOF(struct in_addr, ,
|
||||
|
||||
AC_CHECK_FUNCS([bitncmp if_indextoname])
|
||||
|
||||
dnl God bless non-standardized functions! We need to see which getservbyport_r variant is available
|
||||
CARES_CHECK_GETSERVBYPORT_R
|
||||
|
||||
CURL_CHECK_NONBLOCKING_SOCKET
|
||||
|
||||
AC_OUTPUT(Makefile)
|
||||
|
@@ -209,7 +209,7 @@ ${LIBTOOLIZE:-libtoolize} --copy --automake --force || die "The libtool command
|
||||
fi
|
||||
|
||||
echo "buildconf: running automake"
|
||||
${AUTOMAKE:-automake} -a || die "The automake command failed"
|
||||
${AUTOMAKE:-automake} -a -c || die "The automake command failed"
|
||||
|
||||
echo "buildconf: OK"
|
||||
exit 0
|
||||
|
25
configure.ac
25
configure.ac
@@ -122,13 +122,13 @@ case $host in
|
||||
*-*-mingw*)
|
||||
AC_DEFINE(BUILDING_LIBCURL, 1, [when building libcurl itself])
|
||||
AC_MSG_RESULT(yes)
|
||||
<EFBFBD> <20>AC_MSG_CHECKING([if we need CURL_STATICLIB])
|
||||
AC_MSG_CHECKING([if we need CURL_STATICLIB])
|
||||
if test "X$enable_shared" = "Xno"
|
||||
then
|
||||
AC_DEFINE(CURL_STATICLIB, 1, [when not building a shared library])
|
||||
AC_MSG_RESULT(yes)
|
||||
<EFBFBD> <20>else
|
||||
<EFBFBD> <20> <20>AC_MSG_RESULT(no)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
@@ -251,6 +251,21 @@ AC_HELP_STRING([--disable-telnet],[Disable TELNET support]),
|
||||
esac ],
|
||||
AC_MSG_RESULT(yes)
|
||||
)
|
||||
AC_MSG_CHECKING([whether to support tftp])
|
||||
AC_ARG_ENABLE(tftp,
|
||||
AC_HELP_STRING([--enable-tftp],[Enable TFTP support])
|
||||
AC_HELP_STRING([--disable-tftp],[Disable TFTP support]),
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
AC_DEFINE(CURL_DISABLE_TFTP, 1, [to disable TFTP])
|
||||
AC_SUBST(CURL_DISABLE_TFTP, [1])
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
;;
|
||||
esac ],
|
||||
AC_MSG_RESULT(yes)
|
||||
)
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Check for built-in manual
|
||||
@@ -1419,6 +1434,8 @@ AC_CHECK_HEADERS(
|
||||
libgen.h \
|
||||
locale.h \
|
||||
errno.h \
|
||||
arpa/tftp.h \
|
||||
sys/filio.h \
|
||||
setjmp.h,
|
||||
dnl to do if not found
|
||||
[],
|
||||
@@ -1673,7 +1690,7 @@ AC_HELP_STRING([--disable-ares],[Disable ares for name lookups]),
|
||||
*) AC_MSG_RESULT(yes)
|
||||
|
||||
if test "x$IPV6_ENABLED" = "x1"; then
|
||||
AC_MSG_ERROR([ares doesn't work with ipv6, disable ipv6 to use ares])
|
||||
AC_MSG_NOTICE([ares may not work properly with ipv6])
|
||||
fi
|
||||
|
||||
AC_DEFINE(USE_ARES, 1, [Define if you want to enable ares support])
|
||||
|
@@ -116,6 +116,9 @@ while test $# -gt 0; do
|
||||
if test "@CURL_DISABLE_DICT@" != "1"; then
|
||||
echo "DICT"
|
||||
fi
|
||||
if test "@CURL_DISABLE_TFTP@" != "1"; then
|
||||
echo "TFTP"
|
||||
fi
|
||||
;;
|
||||
--version)
|
||||
echo libcurl @VERSION@
|
||||
|
@@ -150,6 +150,11 @@ Scheme
|
||||
Bigloo binding written by Kirill Lisovsky
|
||||
http://curl.haxx.se/libcurl/scheme/
|
||||
|
||||
S-Lang
|
||||
|
||||
S-Lang binding written by John E Davis
|
||||
http://www.jedsoft.org/slang/modules/curl.html
|
||||
|
||||
Tcl
|
||||
|
||||
Tclcurl is written by Andr<64>s Garc<72>a
|
||||
@@ -161,7 +166,7 @@ Visual Basic
|
||||
http://sourceforge.net/projects/libcurl-vb/
|
||||
|
||||
Q
|
||||
|
||||
The libcurl module is part of the default install
|
||||
http://q-lang.sourceforge.net/
|
||||
|
||||
wxWidgets
|
||||
|
@@ -1,12 +1,12 @@
|
||||
Date: September 1, 2005
|
||||
Author: Daniel Stenberg <daniel@haxx.se>
|
||||
URL: http://curl.haxx.se/legal/distro-dilemma.html
|
||||
Date: September 30, 2005
|
||||
Author: Daniel Stenberg <daniel@haxx.se>
|
||||
URL: http://curl.haxx.se/legal/distro-dilemma.html
|
||||
|
||||
Condition
|
||||
|
||||
This document is written to describe the sitution as it is right now. libcurl
|
||||
7.14.0 is currently the latest version available. Things may (or perhaps
|
||||
will) of course change in the future.
|
||||
This document is written to describe the situation as it is right
|
||||
now. libcurl 7.14.1 is currently the latest version available. Things may (or
|
||||
perhaps will) of course change in the future.
|
||||
|
||||
This document reflects my view and understanding of these things. Please tell
|
||||
me where and how you think I'm wrong, and I'll try to correct my mistakes.
|
||||
@@ -16,7 +16,7 @@ Background
|
||||
The Free Software Foundation has deemed the Original BSD license[1] to be
|
||||
"incompatible"[2] with GPL[3]. I'd rather say it is the other way around, but
|
||||
the point is the same: if you distribute a binary version of a GPL program,
|
||||
it MUST NOT be linked with any Original BSD-licenced parts or
|
||||
it MUST NOT be linked with any Original BSD-licensed parts or
|
||||
libraries. Doing so will violate the GPL license. For a long time, very many
|
||||
GPL licensed programs have avoided this license mess by adding an
|
||||
exception[8] to their license. And many others have just closed their eyes
|
||||
@@ -38,7 +38,7 @@ Background
|
||||
Part of the Operating System
|
||||
|
||||
This would not be a problem if the used lib would be considered part of the
|
||||
uderlying operating system, as then the GPL license has an exception
|
||||
underlying operating system, as then the GPL license has an exception
|
||||
clause[6] that allows applications to use such libs without having to be
|
||||
allowed to distribute it or its sources. Possibly some distros will claim
|
||||
that OpenSSL is part of their operating system.
|
||||
@@ -92,8 +92,13 @@ The Better License, Original BSD or LGPL?
|
||||
Instead, I think we should accept the fact that the SSL/TLS libraries and
|
||||
their different licenses will fit different applications and their authors
|
||||
differently depending on the applications' licenses and their general usage
|
||||
pattern (considering how LGPL libraries can be burdonsome for embedded
|
||||
systems usage).
|
||||
pattern (considering how LGPL libraries for example can be burdensome for
|
||||
embedded systems usage).
|
||||
|
||||
In Debian land, there seems to be a common opinion that LGPL is "maximally
|
||||
compatible" with apps while Original BSD is not. Like this:
|
||||
|
||||
http://lists.debian.org/debian-devel/2005/09/msg01417.html
|
||||
|
||||
More SSL Libraries
|
||||
|
||||
@@ -116,6 +121,16 @@ Project cURL Angle of this Problem
|
||||
affects users - GPL application authors only - of our lib as it comes
|
||||
included and delivered on some distros.
|
||||
|
||||
libcurl has different ABI when built with different SSL/TLS libraries due to
|
||||
two reasons:
|
||||
|
||||
1. No one has worked on fixing this. The mutex/lock callbacks should be set
|
||||
with a generic libcurl function that should use the proper underlying
|
||||
functions.
|
||||
|
||||
2. The CURLOPT_SSL_CTX_FUNCTION option is not possible to "emulate" on GnuTLS
|
||||
but simply requires OpenSSL.
|
||||
|
||||
Distro Angle of this Problem
|
||||
|
||||
A distro can provide separate libcurls built with different SSL/TLS libraries
|
||||
@@ -170,6 +185,10 @@ When Will This Happen
|
||||
code like today (without the use of lib2), should you decide to ignore the
|
||||
problems outlined in this document.
|
||||
|
||||
Update: Work on this has been initiated by Richard Atterer:
|
||||
|
||||
http://curl.haxx.se/mail/lib-2005-09/0066.html
|
||||
|
||||
Footnotes
|
||||
|
||||
[1] = http://www.xfree86.org/3.3.6/COPYRIGHT2.html#6
|
||||
|
@@ -145,3 +145,9 @@ August 2004:
|
||||
April 2005:
|
||||
|
||||
GnuTLS can now optionally be used for the secure layer when curl is built.
|
||||
|
||||
September 2005:
|
||||
|
||||
TFTP support was added.
|
||||
|
||||
More than 100,000 unique visitors of the curl web site. 25 mirrors.
|
||||
|
@@ -3,6 +3,10 @@ join in and help us correct one or more of these! Also be sure to check the
|
||||
changelog of the current development status, as one or more of these problems
|
||||
may have been fixed since this was written!
|
||||
|
||||
26. NTLM authentication using SSPI (on Windows) when (lib)curl is running in
|
||||
"system context" will make it use wrong(?) user name - at least when compared
|
||||
to what winhttp does. See http://curl.haxx.se/bug/view.cgi?id=1281867
|
||||
|
||||
25. When doing a CONNECT request with curl it doesn't properly handle if the
|
||||
proxy closes the connection within the authentication "negotiation phase".
|
||||
Like if you do HTTPS or similar over a proxy and you use perhaps
|
||||
@@ -23,7 +27,7 @@ may have been fixed since this was written!
|
||||
complaining on "unaligned file size" on completion. The problem is related
|
||||
to VMS file structures and the perceived file sizes stat() returns. A
|
||||
possible fix would involve sending a "STRU VMS" command.
|
||||
http://sourceforge.net/support/tracker.php?aid=1156287
|
||||
http://curl.haxx.se/bug/view.cgi?id=1156287
|
||||
|
||||
21. FTP ASCII transfers do not follow RFC959. They don't convert the data
|
||||
accordingly (not for sending nor for receiving). RFC 959 section 3.1.1.1
|
||||
@@ -69,11 +73,12 @@ may have been fixed since this was written!
|
||||
10. To get HTTP Negotiate authentication to work fine, you need to provide a
|
||||
(fake) user name (this concerns both curl and the lib) because the code
|
||||
wrongly only considers authentication if there's a user name provided.
|
||||
Bug report #1004841. How? http://curl.haxx.se/mail/lib-2004-08/0182.html
|
||||
http://curl.haxx.se/bug/view.cgi?id=1004841. How?
|
||||
http://curl.haxx.se/mail/lib-2004-08/0182.html
|
||||
|
||||
9. --limit-rate using -d or -F does not work. This is because the limit logic
|
||||
is provided by the curl app in its read/write callbacks, and when doing
|
||||
-d/-F the callbacks aren't used! Bug report #921395.
|
||||
-d/-F the callbacks aren't used! http://curl.haxx.se/bug/view.cgi?id=921395
|
||||
|
||||
8. Doing resumed upload over HTTP does not work with '-C -', because curl
|
||||
doesn't do a HEAD first to get the initial size. This needs to be done
|
||||
|
26
docs/THANKS
26
docs/THANKS
@@ -9,15 +9,14 @@ Alan Pinstein
|
||||
Albert Chin-A-Young
|
||||
Albert Choy
|
||||
Aleksandar Milivojevic
|
||||
Alex aka WindEagle
|
||||
Alex Neblett
|
||||
Alex Suykov
|
||||
Alex aka WindEagle
|
||||
Alexander Kourakos
|
||||
Alexander Krasnostavsky
|
||||
Alexander Zhuravlev
|
||||
Alexis Carvalho
|
||||
Andi Jahja
|
||||
Andr<EFBFBD>s Garc<72>a
|
||||
Andreas Damm
|
||||
Andreas Olsson
|
||||
Andreas Rieke
|
||||
@@ -25,6 +24,7 @@ Andres Garcia
|
||||
Andrew Bushnell
|
||||
Andrew Francis
|
||||
Andrew Fuller
|
||||
Andr<EFBFBD>s Garc<72>a
|
||||
Andy Cedilnik
|
||||
Andy Serpa
|
||||
Angus Mackay
|
||||
@@ -36,8 +36,8 @@ Avery Fay
|
||||
Ben Greear
|
||||
Benjamin Gerard
|
||||
Bertrand Demiddelaer
|
||||
Bj<EFBFBD>rn Stenberg
|
||||
Bjorn Reese
|
||||
Bj<EFBFBD>rn Stenberg
|
||||
Bob Schader
|
||||
Brad Burdick
|
||||
Brent Beardsley
|
||||
@@ -75,8 +75,8 @@ Dan C
|
||||
Dan Fandrich
|
||||
Dan Torop
|
||||
Dan Zitter
|
||||
Daniel at touchtunes
|
||||
Daniel Stenberg
|
||||
Daniel at touchtunes
|
||||
Dave Dribin
|
||||
Dave Halbakken
|
||||
Dave Hamilton
|
||||
@@ -138,8 +138,6 @@ Frank Ticheler
|
||||
Fred New
|
||||
Fred Noz
|
||||
Frederic Lepied
|
||||
G<EFBFBD>nter Knauf
|
||||
G<EFBFBD>tz Babin-Ebell
|
||||
Gautam Mani
|
||||
Gaz Iqbal
|
||||
Georg Horn
|
||||
@@ -162,6 +160,8 @@ Guenole Bescon
|
||||
Guillaume Arluison
|
||||
Gustaf Hui
|
||||
Gwenole Beauchesne
|
||||
G<EFBFBD>tz Babin-Ebell
|
||||
G<EFBFBD>nter Knauf
|
||||
Hamish Mackenzie
|
||||
Hanno Kranzhoff
|
||||
Hans Steegers
|
||||
@@ -174,11 +174,10 @@ Ian Ford
|
||||
Ian Gulliver
|
||||
Ian Wilkes
|
||||
Ignacio Vazquez-Abrams
|
||||
Igor Polyakov
|
||||
Ilguiz Latypov
|
||||
Ingo Ralf Blum
|
||||
Ingo Wilken
|
||||
J<EFBFBD>rg Mueller-Tolk
|
||||
J<EFBFBD>rn Hartroth
|
||||
Jacky Lam
|
||||
Jacob Meuser
|
||||
James Bursa
|
||||
@@ -225,6 +224,8 @@ Jukka Pihl
|
||||
Julian Noble
|
||||
Jun-ichiro itojun Hagino
|
||||
Jurij Smakov
|
||||
J<EFBFBD>rg Mueller-Tolk
|
||||
J<EFBFBD>rn Hartroth
|
||||
Kai Sommerfeld
|
||||
Kai-Uwe Rommel
|
||||
Kang-Jin Lee
|
||||
@@ -234,6 +235,7 @@ Keith McGuigan
|
||||
Ken Hirsch
|
||||
Ken Rastatter
|
||||
Kevin Fisk
|
||||
Kevin Lussier
|
||||
Kevin Roth
|
||||
Kimmo Kinnunen
|
||||
Kjell Ericson
|
||||
@@ -312,8 +314,8 @@ Nicolas Berloquin
|
||||
Nicolas Croiset
|
||||
Niels van Tongeren
|
||||
Nikita Schmidt
|
||||
nk
|
||||
Nodak Sodak
|
||||
Norbert Novotny
|
||||
Oren Tirosh
|
||||
P R Schaffner
|
||||
Patrick Bihan-Faou
|
||||
@@ -376,7 +378,6 @@ Rosimildo da Silva
|
||||
Roy Shan
|
||||
Rune Kleveland
|
||||
Ryan Nelson
|
||||
S<EFBFBD>bastien Willemijns
|
||||
S. Moonesamy
|
||||
Salvador D<>vila
|
||||
Salvatore Sorrentino
|
||||
@@ -392,6 +393,7 @@ Shard
|
||||
Shawn Poulson
|
||||
Siddhartha Prakash Jain
|
||||
Simon Dick
|
||||
Simon Josefsson
|
||||
Simon Liu
|
||||
Spiridonoff A.V
|
||||
Stadler Stephan
|
||||
@@ -408,7 +410,7 @@ Steven Bazyl
|
||||
Steven G. Johnson
|
||||
Stoned Elipot
|
||||
Sven Neuhaus
|
||||
swalkaus at yahoo.com
|
||||
S<EFBFBD>bastien Willemijns
|
||||
T. Bharath
|
||||
T. Yamada
|
||||
Thomas Schwinge
|
||||
@@ -451,3 +453,5 @@ Wilfredo Sanchez
|
||||
Wojciech Zwiefka
|
||||
Yarram Sunil
|
||||
Zvi Har'El
|
||||
nk
|
||||
swalkaus at yahoo.com
|
||||
|
@@ -31,7 +31,7 @@ TODO
|
||||
* Introduce a new error code indicating authentication problems (for proxy
|
||||
CONNECT error 407 for example). This cannot be an error code, we must not
|
||||
return informational stuff as errors, consider a new info returned by
|
||||
curl_easy_getinfo() #845941
|
||||
curl_easy_getinfo() http://curl.haxx.se/bug/view.cgi?id=845941
|
||||
|
||||
* Use 'struct lifreq' and SIOCGLIFADDR instead of 'struct ifreq' and
|
||||
SIOCGIFADDR on newer Solaris versions as they claim the latter is obsolete.
|
||||
|
27
docs/curl.1
27
docs/curl.1
@@ -21,7 +21,7 @@
|
||||
.\" * $Id$
|
||||
.\" **************************************************************************
|
||||
.\"
|
||||
.TH curl 1 "12 Aug 2005" "Curl 7.14.1" "Curl Manual"
|
||||
.TH curl 1 "4 Sep 2005" "Curl 7.14.2" "Curl Manual"
|
||||
.SH NAME
|
||||
curl \- transfer a URL
|
||||
.SH SYNOPSIS
|
||||
@@ -30,8 +30,8 @@ curl \- transfer a URL
|
||||
.SH DESCRIPTION
|
||||
.B curl
|
||||
is a tool to transfer data from or to a server, using one of the supported
|
||||
protocols (HTTP, HTTPS, FTP, FTPS, GOPHER, DICT, TELNET, LDAP or FILE). The
|
||||
command is designed to work without user interaction.
|
||||
protocols (HTTP, HTTPS, FTP, FTPS, TFTP, GOPHER, DICT, TELNET, LDAP or
|
||||
FILE). The command is designed to work without user interaction.
|
||||
|
||||
curl offers a busload of useful tricks like proxy support, user
|
||||
authentication, ftp upload, HTTP post, SSL (https:) connections, cookies, file
|
||||
@@ -64,6 +64,11 @@ several ones next to each other:
|
||||
You can specify any amount of URLs on the command line. They will be fetched
|
||||
in a sequential manner in the specified order.
|
||||
|
||||
If you specify URL without protocol:// prefix, curl will attempt to guess what
|
||||
protocol you might want. It will then default to HTTP but try other protocols
|
||||
based on often-used host name prefixes. For example, for host names starting
|
||||
with "ftp." curl will assume you want to speak FTP.
|
||||
|
||||
Curl will attempt to re-use connections for multiple file transfers, so that
|
||||
getting many files from the same server will not do multiple connects /
|
||||
handshakes. This improves speed. Of course this is only done on files
|
||||
@@ -347,6 +352,15 @@ If this option is used twice, the second will again disable silent failure.
|
||||
using this option can be used to override a previous --ftp-port option. (Added
|
||||
in 7.11.0)
|
||||
|
||||
If this option is used twice, the second will again disable silent failure.
|
||||
.IP "--ftp-skip-pasv-ip"
|
||||
(FTP) Tell curl to not use the IP address the server suggests in its response
|
||||
to curl's PASV command when curl connects the data connection. Instead curl
|
||||
will re-use the same IP address it already uses for the control
|
||||
connection. (Added in 7.14.2)
|
||||
|
||||
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
|
||||
|
||||
If this option is used twice, the second will again disable silent failure.
|
||||
.IP "--ftp-ssl"
|
||||
(FTP) Make the FTP connection switch to use SSL/TLS. (Added in 7.11.0)
|
||||
@@ -579,8 +593,7 @@ this given limit. This concerns both FTP and HTTP transfers.
|
||||
.IP "-m/--max-time <seconds>"
|
||||
Maximum time in seconds that you allow the whole operation to take. This is
|
||||
useful for preventing your batch jobs from hanging for hours due to slow
|
||||
networks or links going down. This doesn't work fully in win32 systems. See
|
||||
also the \fI--connect-timeout\fP option.
|
||||
networks or links going down. See also the \fI--connect-timeout\fP option.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-M/--manual"
|
||||
@@ -599,7 +612,7 @@ directory.
|
||||
|
||||
A quick and very simple example of how to setup a \fI.netrc\fP to allow curl
|
||||
to ftp to the machine host.domain.com with user name \&'myself' and password
|
||||
'secret' should look similar to:
|
||||
\&'secret' should look similar to:
|
||||
|
||||
.B "machine host.domain.com login myself password secret"
|
||||
|
||||
@@ -1171,7 +1184,7 @@ Sets proxy server to use for GOPHER.
|
||||
Sets proxy server to use if no protocol-specific proxy is set.
|
||||
.IP "NO_PROXY <comma-separated list of hosts>"
|
||||
list of host names that shouldn't go through any proxy. If set to a asterisk
|
||||
'*' only, it matches all hosts.
|
||||
\&'*' only, it matches all hosts.
|
||||
.SH EXIT CODES
|
||||
There exists a bunch of different error codes and their corresponding error
|
||||
messages that may appear during bad conditions. At the time of this writing,
|
||||
|
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/types.h>
|
||||
@@ -93,5 +95,8 @@ int main(int argc, char **argv)
|
||||
* you're done with it, you should free() it as a nice application.
|
||||
*/
|
||||
|
||||
if(chunk.memory)
|
||||
free(chunk.memory);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -52,8 +52,7 @@ PDFPAGES = curl_easy_cleanup.pdf curl_easy_getinfo.pdf \
|
||||
|
||||
CLEANFILES = $(HTMLPAGES) $(PDFPAGES)
|
||||
|
||||
EXTRA_DIST = $(man_MANS) $(HTMLPAGES) index.html $(PDFPAGES) libcurl.m4 \
|
||||
getinfo-times
|
||||
EXTRA_DIST = $(man_MANS) $(HTMLPAGES) index.html $(PDFPAGES) libcurl.m4
|
||||
|
||||
MAN2HTML= roffit --mandir=. < $< >$@
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_easy_getinfo 3 "22 Dec 2004" "libcurl 7.12.3" "libcurl Manual"
|
||||
.TH curl_easy_getinfo 3 "6 Oct 2005" "libcurl 7.12.3" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_getinfo - extract information from a curl handle
|
||||
.SH SYNOPSIS
|
||||
@@ -141,6 +141,40 @@ cookies cURL knows (expired ones, too). Don't forget to
|
||||
cookies (cookies for the handle have not been enabled or simply none have been
|
||||
received) 'struct curl_slist *' will be set to point to NULL. (Added in
|
||||
7.14.1)
|
||||
.SH TIMES
|
||||
.NF
|
||||
An overview of the six time values available from curl_easy_getinfo()
|
||||
|
||||
curk_easy_perform()
|
||||
|
|
||||
|--NT
|
||||
|--|--CT
|
||||
|--|--|--PT
|
||||
|--|--|--|--ST
|
||||
|--|--|--TT
|
||||
|--|--|--|--|--RT
|
||||
.FI
|
||||
.IP NT
|
||||
\fICURLINFO_NAMELOOKUP_TIME\fP. The time it took from the start until the name
|
||||
resolving was completed.
|
||||
.IP CT
|
||||
\fICURLINFO_CONNECT_TIME\fP. The time it took from the start until the connect
|
||||
to the remote host (or proxy) was completed.
|
||||
.IP PT
|
||||
\fICURLINFO_PRETRANSFER_TIME\fP. The time it took from the start until the
|
||||
file transfer is just about to begin. This includes all pre-transfer commands
|
||||
and negotiations that are specific to the particular protocol(s) involved.
|
||||
.IP ST
|
||||
\fICURLINFO_STARTTRANSFER_TIME\fP. The time it took from the start until the
|
||||
first byte is just about to be transferred.
|
||||
.IP TT
|
||||
\fICURLINFO_TOTAL_TIME\fP. Time of the previous transfer. This time does not
|
||||
include the connect time (CT), so if you want the complete operation time, you
|
||||
should add that.
|
||||
.IP RT
|
||||
\fICURLINFO_REDIRECT_TIME\fP. The time it took for all redirection steps
|
||||
include name lookup, connect, pretransfer and transfer before final
|
||||
transaction was started. So, this is zero if no redirection took place.
|
||||
.SH RETURN VALUE
|
||||
If the operation was successful, CURLE_OK is returned. Otherwise an
|
||||
appropriate error code will be returned.
|
||||
|
@@ -21,7 +21,7 @@
|
||||
.\" * $Id$
|
||||
.\" **************************************************************************
|
||||
.\"
|
||||
.TH curl_easy_setopt 3 "28 Jul 2005" "libcurl 7.14.1" "libcurl Manual"
|
||||
.TH curl_easy_setopt 3 "22 Sep 2005" "libcurl 7.14.2" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_setopt - set options for a curl easy handle
|
||||
.SH SYNOPSIS
|
||||
@@ -44,11 +44,11 @@ between transfers, so if you want subsequent transfers with different options,
|
||||
you must change them between the transfers. You can optionally reset all
|
||||
options back to internal default with \fIcurl_easy_reset(3)\fP.
|
||||
|
||||
\fBNOTE:\fP strings passed to libcurl as 'char *' arguments, will not be
|
||||
copied by the library. Instead you should keep them available until libcurl no
|
||||
longer needs them. Failing to do so will cause very odd behavior or even
|
||||
crashes. libcurl will need them until you call \fIcurl_easy_cleanup(3)\fP or
|
||||
you set the same option again to use a different pointer.
|
||||
Strings passed to libcurl as 'char *' arguments, will not be copied by the
|
||||
library. Instead you should keep them available until libcurl no longer needs
|
||||
them. Failing to do so will cause very odd behavior or even crashes. libcurl
|
||||
will need them until you call \fIcurl_easy_cleanup(3)\fP or you set the same
|
||||
option again to use a different pointer.
|
||||
|
||||
The \fIhandle\fP is the return code from a \fIcurl_easy_init(3)\fP or
|
||||
\fIcurl_easy_duphandle(3)\fP call.
|
||||
@@ -70,8 +70,8 @@ preceding the data (like HTTP).
|
||||
A non-zero parameter tells the library to shut off the built-in progress meter
|
||||
completely.
|
||||
|
||||
\fBNOTE:\fP future versions of libcurl is likely to not have any built-in
|
||||
progress meter at all.
|
||||
Future versions of libcurl is likely to not have any built-in progress meter
|
||||
at all.
|
||||
.IP CURLOPT_NOSIGNAL
|
||||
Pass a long. If it is non-zero, libcurl will not use any functions that
|
||||
install signal handlers or any functions that cause signals to be sent to the
|
||||
@@ -96,19 +96,26 @@ transfer and return \fICURLE_WRITE_ERROR\fP.
|
||||
This function may be called with zero bytes data if the transfered file is
|
||||
empty.
|
||||
|
||||
Set this option to NULL to get the internal default function. The internal
|
||||
default function will write the data to the FILE * given with
|
||||
\fICURLOPT_WRITEDATA\fP.
|
||||
|
||||
Set the \fIstream\fP argument with the \fICURLOPT_WRITEDATA\fP option.
|
||||
|
||||
\fBNOTE:\fP you will be passed as much data as possible in all invokes, but
|
||||
you cannot possibly make any assumptions. It may be one byte, it may be
|
||||
The callback function will be passed as much data as possible in all invokes,
|
||||
but you cannot possibly make any assumptions. It may be one byte, it may be
|
||||
thousands. The maximum amount of data that can be passed to the write callback
|
||||
is defined in the curl.h header file: CURL_MAX_WRITE_SIZE.
|
||||
.IP CURLOPT_WRITEDATA
|
||||
Data pointer to pass to the file write function. Note that if you specify the
|
||||
\fICURLOPT_WRITEFUNCTION\fP, this is the pointer you'll get as input. If you
|
||||
don't use a callback, you must pass a 'FILE *' as libcurl will pass this to
|
||||
fwrite() when writing data.
|
||||
Data pointer to pass to the file write function. If you use the
|
||||
\fICURLOPT_WRITEFUNCTION\fP option, this is the pointer you'll get as
|
||||
input. If you don't use a callback, you must pass a 'FILE *' as libcurl will
|
||||
pass this to fwrite() when writing data.
|
||||
|
||||
\fBNOTE:\fP If you're using libcurl as a win32 DLL, you MUST use the
|
||||
The internal \fICURLOPT_WRITEFUNCTION\fP will write the data to the FILE *
|
||||
given with this option, or to stdout if this option hasn't been set.
|
||||
|
||||
If you're using libcurl as a win32 DLL, you \fBMUST\fP use the
|
||||
\fICURLOPT_WRITEFUNCTION\fP if you set this option or you will experience
|
||||
crashes.
|
||||
|
||||
@@ -129,15 +136,20 @@ server expected it, like when you've told you will upload N bytes and you
|
||||
upload less than N bytes), you may experience that the server "hangs" waiting
|
||||
for the rest of the data that won't come.
|
||||
|
||||
In libcurl 7.12.1 and later, the read callback may return
|
||||
\fICURL_READFUNC_ABORT\fP to stop the current operation at once, with a
|
||||
\fICURLE_ABORTED_BY_CALLBACK\fP error code from the transfer.
|
||||
.IP CURLOPT_READDATA
|
||||
Data pointer to pass to the file read function. Note that if you specify the
|
||||
\fICURLOPT_READFUNCTION\fP, this is the pointer you'll get as input. If you
|
||||
don't specify a read callback, this must be a valid FILE *.
|
||||
The read callback may return \fICURL_READFUNC_ABORT\fP to stop the current
|
||||
operation immediately, resulting in a \fICURLE_ABORTED_BY_CALLBACK\fP error
|
||||
code from the transfer (Added in 7.12.1)
|
||||
|
||||
\fBNOTE:\fP If you're using libcurl as a win32 DLL, you MUST use a
|
||||
If you set the callback pointer to NULL, or doesn't set it at all, the default
|
||||
internal read function will be used. It is simply doing an fread() on the FILE
|
||||
* stream set with \fICURLOPT_READDATA\fP.
|
||||
.IP CURLOPT_READDATA
|
||||
Data pointer to pass to the file read function. If you use the
|
||||
\fICURLOPT_READFUNCTION\fP option, this is the pointer you'll get as input. If
|
||||
you don't specify a read callback but instead rely on the default internal
|
||||
read function, this data must be a valid readable FILE *.
|
||||
|
||||
If you're using libcurl as a win32 DLL, you MUST use a
|
||||
\fICURLOPT_READFUNCTION\fP if you set this option.
|
||||
|
||||
This option is also known with the older name \fICURLOPT_INFILE\fP, the name
|
||||
@@ -163,8 +175,8 @@ data, the upload size will remain 0). Returning a non-zero value from this
|
||||
callback will cause libcurl to abort the transfer and return
|
||||
\fICURLE_ABORTED_BY_CALLBACK\fP.
|
||||
|
||||
Also note that \fICURLOPT_NOPROGRESS\fP must be set to FALSE to make this
|
||||
function actually get called.
|
||||
\fICURLOPT_NOPROGRESS\fP must be set to FALSE to make this function actually
|
||||
get called.
|
||||
.IP CURLOPT_PROGRESSDATA
|
||||
Pass a pointer that will be untouched by libcurl and passed as the first
|
||||
argument in the progress callback set with \fICURLOPT_PROGRESSFUNCTION\fP.
|
||||
@@ -236,10 +248,10 @@ option was introduced in 7.11.0.
|
||||
This function will get called on all new connections made to a server, during
|
||||
the SSL negotiation. The SSL_CTX pointer will be a new one every time.
|
||||
|
||||
\fBNOTE:\fP To use this properly, a non-trivial amount of knowledge of the
|
||||
openssl libraries is necessary. Using this function allows for example to use
|
||||
openssl callbacks to add additional validation code for certificates, and even
|
||||
to change the actual URI of an HTTPS request (example used in the lib509 test
|
||||
To use this properly, a non-trivial amount of knowledge of the openssl
|
||||
libraries is necessary. Using this function allows for example to use openssl
|
||||
callbacks to add additional validation code for certificates, and even to
|
||||
change the actual URI of an HTTPS request (example used in the lib509 test
|
||||
case). See also the example section for a replacement of the key, certificate
|
||||
and trust file settings.
|
||||
.IP CURLOPT_SSL_CTX_DATA
|
||||
@@ -249,14 +261,21 @@ parameter, otherwise \fBNULL\fP. (Added in 7.11.0)
|
||||
.SH ERROR OPTIONS
|
||||
.IP CURLOPT_ERRORBUFFER
|
||||
Pass a char * to a buffer that the libcurl may store human readable error
|
||||
messages in. This may be more helpful than just the return code from the
|
||||
library. The buffer must be at least CURL_ERROR_SIZE big.
|
||||
messages in. This may be more helpful than just the return code from
|
||||
\fIcurl_easy_perform\fP. The buffer must be at least CURL_ERROR_SIZE big.
|
||||
|
||||
Use \fICURLOPT_VERBOSE\fP and \fICURLOPT_DEBUGFUNCTION\fP to better
|
||||
debug/trace why errors happen.
|
||||
|
||||
\fBNote:\fP if the library does not return an error, the buffer may not have
|
||||
been touched. Do not rely on the contents in those cases.
|
||||
If the library does not return an error, the buffer may not have been
|
||||
touched. Do not rely on the contents in those cases.
|
||||
|
||||
In a few rare cases, there is no text string associated with the error in
|
||||
libcurl and then you may not get a string in the buffer even though it returns
|
||||
an error. This is considered a bug and we appreciate your reports about these
|
||||
cases. Anyway, you can avoid problems with these cases in your program by
|
||||
making sure to clear the first byte of the error buffer before you call
|
||||
curl_easy_perform().
|
||||
.IP CURLOPT_STDERR
|
||||
Pass a FILE * as parameter. Tell libcurl to use this stream instead of stderr
|
||||
when showing the progress meter and displaying \fICURLOPT_VERBOSE\fP data.
|
||||
@@ -277,7 +296,7 @@ given protocol of the set URL is not supported, libcurl will return on error
|
||||
\fIcurl_multi_perform(3)\fP. Use \fIcurl_version_info(3)\fP for detailed info
|
||||
on which protocols that are supported.
|
||||
|
||||
\fBNOTE:\fP \fICURLOPT_URL\fP is the only option that must be set before
|
||||
\fICURLOPT_URL\fP is the only option that must be set before
|
||||
\fIcurl_easy_perform(3)\fP is called.
|
||||
.IP CURLOPT_PROXY
|
||||
Set HTTP proxy to use. The parameter should be a char * to a zero terminated
|
||||
@@ -310,9 +329,9 @@ this are \fICURLPROXY_HTTP\fP and \fICURLPROXY_SOCKS5\fP, with the HTTP one
|
||||
being default. (Added in 7.10)
|
||||
.IP CURLOPT_HTTPPROXYTUNNEL
|
||||
Set the parameter to non-zero to get the library to tunnel all operations
|
||||
through a given HTTP proxy. Note that there is a big difference between using
|
||||
a proxy and to tunnel through it. If you don't know what this means, you
|
||||
probably don't want this tunneling option.
|
||||
through a given HTTP proxy. There is a big difference between using a proxy
|
||||
and to tunnel through it. If you don't know what this means, you probably
|
||||
don't want this tunneling option.
|
||||
.IP CURLOPT_INTERFACE
|
||||
Pass a char * as parameter. This set the interface name to use as outgoing
|
||||
network interface. The name can be an interface name, an IP address or a host
|
||||
@@ -331,10 +350,14 @@ thread-safe and this will use a global variable.
|
||||
to using the share interface instead! See \fICURLOPT_SHARE\fP and
|
||||
\fIcurl_share_init(3)\fP.
|
||||
.IP CURLOPT_BUFFERSIZE
|
||||
Pass a long specifying your preferred size for the receive buffer in libcurl.
|
||||
The main point of this would be that the write callback gets called more often
|
||||
and with smaller chunks. This is just treated as a request, not an order. You
|
||||
cannot be guaranteed to actually get the given size. (Added in 7.10)
|
||||
Pass a long specifying your preferred size (in bytes) for the receive buffer
|
||||
in libcurl. The main point of this would be that the write callback gets
|
||||
called more often and with smaller chunks. This is just treated as a request,
|
||||
not an order. You cannot be guaranteed to actually get the given size. (Added
|
||||
in 7.10)
|
||||
|
||||
This size is by default set as big as possible (CURL_MAX_WRITE_SIZE), so it
|
||||
only makse sense to use this option if you want it smaller.
|
||||
.IP CURLOPT_PORT
|
||||
Pass a long specifying what remote port number to connect to, instead of the
|
||||
one specified in the URL or the default port for the used protocol.
|
||||
@@ -360,9 +383,9 @@ This parameter controls the preference of libcurl between using user names and
|
||||
passwords from your \fI~/.netrc\fP file, relative to user names and passwords
|
||||
in the URL supplied with \fICURLOPT_URL\fP.
|
||||
|
||||
\fBNote:\fP libcurl uses a user name (and supplied or prompted password)
|
||||
supplied with \fICURLOPT_USERPWD\fP in preference to any of the options
|
||||
controlled by this parameter.
|
||||
libcurl uses a user name (and supplied or prompted password) supplied with
|
||||
\fICURLOPT_USERPWD\fP in preference to any of the options controlled by this
|
||||
parameter.
|
||||
|
||||
Pass a long, set to one of the values described below.
|
||||
.RS
|
||||
@@ -386,9 +409,8 @@ and to search the file with the host only.
|
||||
Only machine name, user name and password are taken into account
|
||||
(init macros and similar things aren't supported).
|
||||
|
||||
\fBNote:\fP libcurl does not verify that the file has the correct properties
|
||||
set (as the standard Unix ftp client does). It should only be readable by
|
||||
user.
|
||||
libcurl does not verify that the file has the correct properties set (as the
|
||||
standard Unix ftp client does). It should only be readable by user.
|
||||
.IP CURLOPT_NETRC_FILE
|
||||
Pass a char * as parameter, pointing to a zero terminated string containing
|
||||
the full path name to the file you want libcurl to use as .netrc file. If this
|
||||
@@ -413,9 +435,9 @@ Pass a long as parameter, which is set to a bitmask, to tell libcurl what
|
||||
authentication method(s) you want it to use. The available bits are listed
|
||||
below. If more than one bit is set, libcurl will first query the site to see
|
||||
what authentication methods it supports and then pick the best one you allow
|
||||
it to use. Note that for some methods, this will induce an extra network
|
||||
round-trip. Set the actual name and password with the \fICURLOPT_USERPWD\fP
|
||||
option. (Added in 7.10.6)
|
||||
it to use. For some methods, this will induce an extra network round-trip. Set
|
||||
the actual name and password with the \fICURLOPT_USERPWD\fP option. (Added in
|
||||
7.10.6)
|
||||
.RS
|
||||
.IP CURLAUTH_BASIC
|
||||
HTTP Basic authentication. This is the default choice, and the only method
|
||||
@@ -433,15 +455,14 @@ applications. It is primarily meant as a support for Kerberos5 authentication
|
||||
but may be also used along with another authentication methods. For more
|
||||
information see IETF draft draft-brezak-spnego-http-04.txt.
|
||||
|
||||
\fBNOTE\fP that you need to build libcurl with a suitable GSS-API library for
|
||||
this to work.
|
||||
You need to build libcurl with a suitable GSS-API library for this to work.
|
||||
.IP CURLAUTH_NTLM
|
||||
HTTP NTLM authentication. A proprietary protocol invented and used by
|
||||
Microsoft. It uses a challenge-response and hash concept similar to Digest, to
|
||||
prevent the password from being eavesdropped.
|
||||
|
||||
\fBNOTE\fP that you need to build libcurl with SSL support for this option to
|
||||
work.
|
||||
You need to build libcurl with OpenSSL support for this option to work, or
|
||||
build libcurl on Windows.
|
||||
.IP CURLAUTH_ANY
|
||||
This is a convenience macro that sets all bits and thus makes libcurl pick any
|
||||
it finds suitable. libcurl will automatically select the one it finds most
|
||||
@@ -456,11 +477,11 @@ Pass a long as parameter, which is set to a bitmask, to tell libcurl what
|
||||
authentication method(s) you want it to use for your proxy authentication. If
|
||||
more than one bit is set, libcurl will first query the site to see what
|
||||
authentication methods it supports and then pick the best one you allow it to
|
||||
use. Note that for some methods, this will induce an extra network
|
||||
round-trip. Set the actual name and password with the
|
||||
\fICURLOPT_PROXYUSERPWD\fP option. The bitmask can be constructed by or'ing
|
||||
together the bits listed above for the \fICURLOPT_HTTPAUTH\fP option. As of
|
||||
this writing, only Basic, Digest and NTLM work. (Added in 7.10.7)
|
||||
use. For some methods, this will induce an extra network round-trip. Set the
|
||||
actual name and password with the \fICURLOPT_PROXYUSERPWD\fP option. The
|
||||
bitmask can be constructed by or'ing together the bits listed above for the
|
||||
\fICURLOPT_HTTPAUTH\fP option. As of this writing, only Basic, Digest and NTLM
|
||||
work. (Added in 7.10.7)
|
||||
.SH HTTP OPTIONS
|
||||
.IP CURLOPT_AUTOREFERER
|
||||
Pass a non-zero parameter to enable this. When enabled, libcurl will
|
||||
@@ -483,14 +504,14 @@ lib/README.encoding for details.
|
||||
A non-zero parameter tells the library to follow any Location: header that the
|
||||
server sends as part of an HTTP header.
|
||||
|
||||
\fBNOTE:\fP this means that the library will re-send the same request on the
|
||||
new location and follow new Location: headers all the way until no more such
|
||||
headers are returned. \fICURLOPT_MAXREDIRS\fP can be used to limit the number
|
||||
of redirects libcurl will follow.
|
||||
This means that the library will re-send the same request on the new location
|
||||
and follow new Location: headers all the way until no more such headers are
|
||||
returned. \fICURLOPT_MAXREDIRS\fP can be used to limit the number of redirects
|
||||
libcurl will follow.
|
||||
.IP CURLOPT_UNRESTRICTED_AUTH
|
||||
A non-zero parameter tells the library it can continue to send authentication
|
||||
(user+password) when following locations, even when hostname changed. Note
|
||||
that this is meaningful only when setting \fICURLOPT_FOLLOWLOCATION\fP.
|
||||
(user+password) when following locations, even when hostname changed. This
|
||||
option is meaningful only when setting \fICURLOPT_FOLLOWLOCATION\fP.
|
||||
.IP CURLOPT_MAXREDIRS
|
||||
Pass a long. The set number will be the redirection limit. If that many
|
||||
redirections have been followed, the next redirect will cause an error
|
||||
@@ -549,8 +570,8 @@ commonly used one by HTML forms. See also the \fICURLOPT_POST\fP. Using
|
||||
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header.
|
||||
You can disable this header with \fICURLOPT_HTTPHEADER\fP as usual.
|
||||
|
||||
\fBNote:\fP to make multipart/formdata posts (aka rfc1867-posts), check out
|
||||
the \fICURLOPT_HTTPPOST\fP option.
|
||||
To make multipart/formdata posts (aka rfc1867-posts), check out the
|
||||
\fICURLOPT_HTTPPOST\fP option.
|
||||
.IP CURLOPT_POSTFIELDSIZE
|
||||
If you want to post data to the server without letting libcurl do a strlen()
|
||||
to measure the data size, this option must be used. When this option is used
|
||||
@@ -605,7 +626,7 @@ request-line are headers.
|
||||
|
||||
Pass a NULL to this to reset back to no custom headers.
|
||||
|
||||
\fBNOTE:\fP The most commonly replaced headers have "shortcuts" in the options
|
||||
The most commonly replaced headers have "shortcuts" in the options
|
||||
\fICURLOPT_COOKIE\fP, \fICURLOPT_USERAGENT\fP and \fICURLOPT_REFERER\fP.
|
||||
.IP CURLOPT_HTTP200ALIASES
|
||||
Pass a pointer to a linked list of aliases to be treated as valid HTTP 200
|
||||
@@ -618,9 +639,9 @@ The linked list should be a fully valid list of struct curl_slist structs, and
|
||||
be properly filled in. Use \fIcurl_slist_append(3)\fP to create the list and
|
||||
\fIcurl_slist_free_all(3)\fP to clean up an entire list.
|
||||
|
||||
\fBNOTE:\fP The alias itself is not parsed for any version strings. So if your
|
||||
alias is "MYHTTP/9.9", Libcurl will not treat the server as responding with
|
||||
HTTP version 9.9. Instead Libcurl will use the value set by option
|
||||
The alias itself is not parsed for any version strings. So if your alias is
|
||||
\&"MYHTTP/9.9", Libcurl will not treat the server as responding with HTTP
|
||||
version 9.9. Instead Libcurl will use the value set by option
|
||||
\fICURLOPT_HTTP_VERSION\fP.
|
||||
.IP CURLOPT_COOKIE
|
||||
Pass a pointer to a zero terminated string as parameter. It will be used to
|
||||
@@ -655,7 +676,7 @@ instead have the cookies written to stdout. Using this option also enables
|
||||
cookies for this session, so if you for example follow a location it will make
|
||||
matching cookies get sent accordingly.
|
||||
|
||||
\fBNOTE:\fP If the cookie jar file can't be created or written to (when the
|
||||
If the cookie jar file can't be created or written to (when the
|
||||
\fIcurl_easy_cleanup(3)\fP is called), libcurl will not and cannot report an
|
||||
error for this. Using \fICURLOPT_VERBOSE\fP or \fICURLOPT_DEBUGFUNCTION\fP
|
||||
will get a warning to display, but that is the only visible feedback you get
|
||||
@@ -762,11 +783,19 @@ directory. (Added in 7.10.7)
|
||||
.IP CURLOPT_FTP_RESPONSE_TIMEOUT
|
||||
Pass a long. Causes curl to set a timeout period (in seconds) on the amount
|
||||
of time that the server is allowed to take in order to generate a response
|
||||
message for a command before the session is considered hung. Note that while
|
||||
curl is waiting for a response, this value overrides \fICURLOPT_TIMEOUT\fP. It
|
||||
is recommended that if used in conjunction with \fICURLOPT_TIMEOUT\fP, you set
|
||||
message for a command before the session is considered hung. While curl is
|
||||
waiting for a response, this value overrides \fICURLOPT_TIMEOUT\fP. It is
|
||||
recommended that if used in conjunction with \fICURLOPT_TIMEOUT\fP, you set
|
||||
\fICURLOPT_FTP_RESPONSE_TIMEOUT\fP to a value smaller than
|
||||
\fICURLOPT_TIMEOUT\fP. (Added in 7.10.8)
|
||||
.IP CURLOPT_FTP_SKIP_PASV_IP
|
||||
Pass a long. If set to a non-zero value, it instructs libcurl to not use the
|
||||
IP address the server suggests in its 227-response to libcurl's PASV command
|
||||
when libcurl connects the data connection. Instead libcurl will re-use the
|
||||
same IP address it already uses for the control connection. But it will use
|
||||
the port number from the 227-response. (Added in 7.14.2)
|
||||
|
||||
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
|
||||
.IP CURLOPT_FTP_SSL
|
||||
Pass a long using one of the values from below, to make libcurl use your
|
||||
desired level of SSL for the ftp transfer. (Added in 7.11.0)
|
||||
@@ -816,10 +845,9 @@ stdout to binary mode. This option can be usable when transferring text data
|
||||
between systems with different views on certain characters, such as newlines
|
||||
or similar.
|
||||
|
||||
\fBNOTE:\fP libcurl does not do a complete ASCII conversion when doing ASCII
|
||||
transfers over FTP. This is a known limitation/flaw that nobody has
|
||||
rectified. libcurl simply sets the mode to ascii and performs a standard
|
||||
transfer.
|
||||
libcurl does not do a complete ASCII conversion when doing ASCII transfers
|
||||
over FTP. This is a known limitation/flaw that nobody has rectified. libcurl
|
||||
simply sets the mode to ascii and performs a standard transfer.
|
||||
.IP CURLOPT_CRLF
|
||||
Convert Unix newlines to CRLF newlines on transfers.
|
||||
.IP CURLOPT_RANGE
|
||||
@@ -845,11 +873,11 @@ server supports the command first.
|
||||
|
||||
Restore to the internal default by setting this to NULL.
|
||||
|
||||
\fBNOTE:\fP Many people have wrongly used this option to replace the entire
|
||||
request with their own, including multiple headers and POST contents. While
|
||||
that might work in many cases, it will cause libcurl to send invalid requests
|
||||
and it could possibly confuse the remote server badly. Use \fICURLOPT_POST\fP
|
||||
and \fICURLOPT_POSTFIELDS\fP to set POST data. Use \fICURLOPT_HTTPHEADER\fP to
|
||||
Many people have wrongly used this option to replace the entire request with
|
||||
their own, including multiple headers and POST contents. While that might work
|
||||
in many cases, it will cause libcurl to send invalid requests and it could
|
||||
possibly confuse the remote server badly. Use \fICURLOPT_POST\fP and
|
||||
\fICURLOPT_POSTFIELDS\fP to set POST data. Use \fICURLOPT_HTTPHEADER\fP to
|
||||
replace or extend the set of headers sent by libcurl. Use
|
||||
\fICURLOPT_HTTP_VERSION\fP to change HTTP version.
|
||||
.IP CURLOPT_FILETIME
|
||||
@@ -893,26 +921,26 @@ Pass a long as parameter. This allows you to specify the maximum size (in
|
||||
bytes) of a file to download. If the file requested is larger than this value,
|
||||
the transfer will not start and CURLE_FILESIZE_EXCEEDED will be returned.
|
||||
|
||||
\fBNOTE:\fP The file size is not always known prior to download, and for such
|
||||
files this option has no effect even if the file transfer ends up being larger
|
||||
than this given limit. This concerns both FTP and HTTP transfers.
|
||||
The file size is not always known prior to download, and for such files this
|
||||
option has no effect even if the file transfer ends up being larger than this
|
||||
given limit. This concerns both FTP and HTTP transfers.
|
||||
.IP CURLOPT_MAXFILESIZE_LARGE
|
||||
Pass a curl_off_t as parameter. This allows you to specify the maximum size
|
||||
(in bytes) of a file to download. If the file requested is larger than this
|
||||
value, the transfer will not start and \fICURLE_FILESIZE_EXCEEDED\fP will be
|
||||
returned. (Added in 7.11.0)
|
||||
|
||||
\fBNOTE:\fP The file size is not always known prior to download, and for such
|
||||
files this option has no effect even if the file transfer ends up being larger
|
||||
than this given limit. This concerns both FTP and HTTP transfers.
|
||||
The file size is not always known prior to download, and for such files this
|
||||
option has no effect even if the file transfer ends up being larger than this
|
||||
given limit. This concerns both FTP and HTTP transfers.
|
||||
.IP CURLOPT_TIMECONDITION
|
||||
Pass a long as parameter. This defines how the \fICURLOPT_TIMEVALUE\fP time
|
||||
value is treated. You can set this parameter to \fICURL_TIMECOND_IFMODSINCE\fP
|
||||
or \fICURL_TIMECOND_IFUNMODSINCE\fP. This feature applies to HTTP and FTP.
|
||||
|
||||
\fBNOTE:\fP The last modification time of a file is not always known and in such
|
||||
instances this feature will have no effect even if the given time condition
|
||||
would have not been met.
|
||||
The last modification time of a file is not always known and in such instances
|
||||
this feature will have no effect even if the given time condition would have
|
||||
not been met.
|
||||
.IP CURLOPT_TIMEVALUE
|
||||
Pass a long as parameter. This should be the time in seconds since 1 jan 1970,
|
||||
and the time will be used in a condition as specified with
|
||||
@@ -925,8 +953,8 @@ considerable time and limiting operations to less than a few minutes risk
|
||||
aborting perfectly normal operations. This option will cause curl to use the
|
||||
SIGALRM to enable time-outing system calls.
|
||||
|
||||
\fBNOTE:\fP this is not recommended to use in unix multi-threaded programs, as
|
||||
it uses signals unless \fICURLOPT_NOSIGNAL\fP (see above) is set.
|
||||
In unix-like systems, this might cause signals to be used unless
|
||||
\fICURLOPT_NOSIGNAL\fP is set.
|
||||
.IP CURLOPT_LOW_SPEED_LIMIT
|
||||
Pass a long as parameter. It contains the transfer speed in bytes per second
|
||||
that the transfer should be below during \fICURLOPT_LOW_SPEED_TIME\fP seconds
|
||||
@@ -947,9 +975,9 @@ When reaching the maximum limit, curl uses the \fICURLOPT_CLOSEPOLICY\fP to
|
||||
figure out which of the existing connections to close to prevent the number of
|
||||
open connections to increase.
|
||||
|
||||
\fBNOTE:\fP if you already have performed transfers with this curl handle,
|
||||
setting a smaller MAXCONNECTS than before may cause open connections to get
|
||||
closed unnecessarily.
|
||||
If you already have performed transfers with this curl handle, setting a
|
||||
smaller MAXCONNECTS than before may cause open connections to get closed
|
||||
unnecessarily.
|
||||
.IP CURLOPT_CLOSEPOLICY
|
||||
Pass a long. This option sets what policy libcurl should use when the
|
||||
connection cache is filled and one of the open connections has to be closed to
|
||||
@@ -981,8 +1009,8 @@ it has connected, this option is of no more use. Set to zero to disable
|
||||
connection timeout (it will then only timeout on the system's internal
|
||||
timeouts). See also the \fICURLOPT_TIMEOUT\fP option.
|
||||
|
||||
\fBNOTE:\fP this is not recommended to use in unix multi-threaded programs, as
|
||||
it uses signals unless \fICURLOPT_NOSIGNAL\fP (see above) is set.
|
||||
In unix-like systems, this might cause signals to be used unless
|
||||
\fICURLOPT_NOSIGNAL\fP is set.
|
||||
.IP CURLOPT_IPRESOLVE
|
||||
Allows an application to select what kind of IP addresses to use when
|
||||
resolving host names. This is only interesting when using host names that
|
||||
@@ -1019,9 +1047,9 @@ changed with \fICURLOPT_SSLKEYTYPE\fP.
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your private key. Supported formats are "PEM", "DER" and "ENG".
|
||||
|
||||
\fBNOTE:\fP The format "ENG" enables you to load the private key from a crypto
|
||||
engine. In this case \fICURLOPT_SSLKEY\fP is used as an identifier passed to
|
||||
the engine. You have to set the crypto engine with \fICURLOPT_SSLENGINE\fP.
|
||||
The format "ENG" enables you to load the private key from a crypto engine. In
|
||||
this case \fICURLOPT_SSLKEY\fP is used as an identifier passed to the
|
||||
engine. You have to set the crypto engine with \fICURLOPT_SSLENGINE\fP.
|
||||
\&"DER" format key file currently does not work because of a bug in OpenSSL.
|
||||
.IP CURLOPT_SSLKEYPASSWD
|
||||
Pass a pointer to a zero terminated string as parameter. It will be used as
|
||||
@@ -1031,14 +1059,14 @@ Pass a pointer to a zero terminated string as parameter. It will be used as
|
||||
the identifier for the crypto engine you want to use for your private
|
||||
key.
|
||||
|
||||
\fBNOTE:\fP If the crypto device cannot be loaded,
|
||||
\fICURLE_SSL_ENGINE_NOTFOUND\fP is returned.
|
||||
If the crypto device cannot be loaded, \fICURLE_SSL_ENGINE_NOTFOUND\fP is
|
||||
returned.
|
||||
.IP CURLOPT_SSLENGINE_DEFAULT
|
||||
Sets the actual crypto engine as the default for (asymmetric) crypto
|
||||
operations.
|
||||
|
||||
\fBNOTE:\fP If the crypto device cannot be set,
|
||||
\fICURLE_SSL_ENGINE_SETFAILED\fP is returned.
|
||||
If the crypto device cannot be set, \fICURLE_SSL_ENGINE_SETFAILED\fP is
|
||||
returned.
|
||||
.IP CURLOPT_SSLVERSION
|
||||
Pass a long as parameter to control what version of SSL/TLS to attempt to use.
|
||||
The available options are:
|
||||
|
@@ -23,4 +23,4 @@ You must curl_free() the returned string when you're done with it.
|
||||
.SH RETURN VALUE
|
||||
A pointer to a zero terminated string or NULL if it failed.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_unescape(3), curl_free(3), RFC 2396
|
||||
.BR curl_unescape "(3), " curl_free "(3), " RFC 2396
|
||||
|
@@ -243,7 +243,7 @@ where it'll store a human readable error message as well.
|
||||
If you then want to transfer another file, the handle is ready to be used
|
||||
again. Mind you, it is even preferred that you re-use an existing handle if
|
||||
you intend to make another transfer. libcurl will then attempt to re-use the
|
||||
previous
|
||||
previous connection.
|
||||
|
||||
.SH "Multi-threading Issues"
|
||||
The first basic rule is that you must \fBnever\fP share a libcurl handle (be
|
||||
|
@@ -309,6 +309,13 @@ typedef enum {
|
||||
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 */
|
||||
CURL_LAST /* never use! */
|
||||
} CURLcode;
|
||||
|
||||
@@ -896,6 +903,12 @@ typedef enum {
|
||||
/* 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),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
|
@@ -28,7 +28,13 @@
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
file origins: */
|
||||
#define LIBCURL_VERSION "7.14.1-CVS"
|
||||
#define LIBCURL_VERSION "7.15.0-CVS"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 15
|
||||
#define LIBCURL_VERSION_PATCH 0
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
|
||||
@@ -37,19 +43,16 @@
|
||||
0xXXYYZZ
|
||||
|
||||
Where XX, YY and ZZ are the main version, release and patch numbers in
|
||||
hexadecimal. All three numbers are always represented using two digits. 1.2
|
||||
would appear as "0x010200" while version 9.11.7 appears as "0x090b07".
|
||||
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 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.
|
||||
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 0x070e01
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 14
|
||||
#define LIBCURL_VERSION_PATCH 1
|
||||
#define LIBCURL_VERSION_NUM ((LIBCURL_VERSION_MAJOR << 16) | \
|
||||
(LIBCURL_VERSION_MINOR << 8) | \
|
||||
LIBCURL_VERSION_PATCH)
|
||||
|
||||
#endif /* __CURL_CURLVER_H */
|
||||
|
@@ -44,7 +44,7 @@ OBJS = $(OBJ_DIR)\transfer.obj $(OBJ_DIR)\file.obj &
|
||||
$(OBJ_DIR)\hostip6.obj $(OBJ_DIR)\inet_ntop.obj &
|
||||
$(OBJ_DIR)\hostsyn.obj $(OBJ_DIR)\parsedate.obj &
|
||||
$(OBJ_DIR)\select.obj $(OBJ_DIR)\sslgen.obj &
|
||||
$(OBJ_DIR)\gtls.obj
|
||||
$(OBJ_DIR)\gtls.obj $(OBJ_DIR)\tftp.obj
|
||||
|
||||
RESOURCE = $(OBJ_DIR)\libcurl.res
|
||||
|
||||
@@ -362,3 +362,9 @@ $(OBJ_DIR)\gtls.obj: gtls.c setup.h config-win32.h
|
||||
$(OBJ_DIR)\sslgen.obj: sslgen.c setup.h config-win32.h urldata.h cookie.h &
|
||||
formdata.h timeval.h http_chunks.h hostip.h hash.h llist.h sslgen.h &
|
||||
ssluse.h gtls.h sendf.h strequal.h url.h memory.h memdebug.h
|
||||
|
||||
$(OBJ_DIR)\tftp.obj: tftp.c setup.h config-win32.h urldata.h cookie.h &
|
||||
..\include\curl\curl.h ..\include\curl\curlver.h ..\include\curl\easy.h &
|
||||
..\include\curl\multi.h formdata.h http_chunks.h hostip.h hash.h llist.h &
|
||||
transfer.h sendf.h tftp.h progress.h ..\include\curl\mprintf.h memory.h &
|
||||
select.h memdebug.h
|
@@ -8,7 +8,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||
content_encoding.c share.c http_digest.c md5.c http_negotiate.c \
|
||||
http_ntlm.c inet_pton.c strtoofft.c strerror.c hostares.c hostasyn.c \
|
||||
hostip4.c hostip6.c hostsyn.c hostthre.c inet_ntop.c parsedate.c \
|
||||
select.c gtls.c sslgen.c
|
||||
select.c gtls.c sslgen.c tftp.c
|
||||
|
||||
HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \
|
||||
progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \
|
||||
@@ -18,5 +18,5 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \
|
||||
share.h md5.h http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h \
|
||||
inet_pton.h strtoofft.h strerror.h inet_ntop.h curlx.h memory.h \
|
||||
setup.h transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h \
|
||||
gtls.h
|
||||
gtls.h tftp.h
|
||||
|
||||
|
@@ -301,7 +301,7 @@ config.h: Makefile.netware
|
||||
@echo $(DL)*/$(DL) >> $@
|
||||
@echo $(DL)#define OS "i586-pc-NetWare"$(DL) >> $@
|
||||
@echo $(DL)#define VERSION "$(LIBCURL_VERSION_STR)"$(DL) >> $@
|
||||
@echo $(DL)#define PACKAGE_BUGREPORT "curl-bug@haxx.se"$(DL) >> $@
|
||||
@echo $(DL)#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"$(DL) >> $@
|
||||
@echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@
|
||||
@echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@
|
||||
@echo $(DL)#define HAVE_DLFCN_H 1$(DL) >> $@
|
||||
|
@@ -469,6 +469,7 @@ X_OBJS= \
|
||||
$(DIROBJ)\strerror.obj \
|
||||
$(DIROBJ)\select.obj \
|
||||
$(DIROBJ)\content_encoding.obj \
|
||||
$(DIROBJ)\tftp.obj \
|
||||
$(RESOURCE)
|
||||
|
||||
all : $(TARGET)
|
||||
|
@@ -631,8 +631,9 @@ singleipconnect(struct connectdata *conn,
|
||||
int error;
|
||||
bool conected;
|
||||
struct SessionHandle *data = conn->data;
|
||||
curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
|
||||
ai->ai_protocol);
|
||||
curl_socket_t sockfd;
|
||||
|
||||
sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
|
||||
if (sockfd == CURL_SOCKET_BAD)
|
||||
return CURL_SOCKET_BAD;
|
||||
|
||||
@@ -660,7 +661,11 @@ singleipconnect(struct connectdata *conn,
|
||||
/* set socket non-blocking */
|
||||
Curl_nonblock(sockfd, TRUE);
|
||||
|
||||
rc = connect(sockfd, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
/* Connect TCP sockets, bind UDP */
|
||||
if(conn->socktype == SOCK_STREAM)
|
||||
rc = connect(sockfd, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
if(-1 == rc) {
|
||||
error = Curl_ourerrno();
|
||||
|
67
lib/ftp.c
67
lib/ftp.c
@@ -174,13 +174,9 @@ static bool isBadFtpString(const char *string)
|
||||
* to us. This function will sit and wait here until the server has
|
||||
* connected.
|
||||
*
|
||||
* If FTP-SSL is used and SSL is requested for the data connection, this
|
||||
* function will do that transport layer handshake too.
|
||||
*
|
||||
*/
|
||||
static CURLcode AllowServerConnect(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result;
|
||||
int timeout_ms;
|
||||
struct SessionHandle *data = conn->data;
|
||||
curl_socket_t sock = conn->sock[SECONDARYSOCKET];
|
||||
@@ -235,17 +231,6 @@ static CURLcode AllowServerConnect(struct connectdata *conn)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If PASV is used, this is is made elsewhere */
|
||||
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;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -858,7 +843,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
|
||||
* Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
|
||||
*/
|
||||
if (ai->ai_socktype == 0)
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
ai->ai_socktype = conn->socktype;
|
||||
|
||||
portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (portsock == CURL_SOCKET_BAD) {
|
||||
@@ -1601,8 +1586,18 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
return CURLE_FTP_WEIRD_227_FORMAT;
|
||||
}
|
||||
|
||||
snprintf(newhost, sizeof(newhost),
|
||||
"%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
||||
/* 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);
|
||||
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(ftp->count1 == 0) {
|
||||
@@ -1622,8 +1617,6 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
return CURLE_FTP_WEIRD_PASV_REPLY;
|
||||
}
|
||||
|
||||
/* we got OK from server */
|
||||
|
||||
if(data->change.proxy && *data->change.proxy) {
|
||||
/*
|
||||
* This is a tunnel through a http proxy and we need to connect to the
|
||||
@@ -1805,7 +1798,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
|
||||
switch(data->set.timecondition) {
|
||||
case CURL_TIMECOND_IFMODSINCE:
|
||||
default:
|
||||
if(data->info.filetime < data->set.timevalue) {
|
||||
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);
|
||||
@@ -2032,6 +2025,16 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
|
||||
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
|
||||
@@ -2131,6 +2134,15 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
|
||||
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 > conn->maxdownload && conn->maxdownload > 0)
|
||||
size = conn->size = conn->maxdownload;
|
||||
|
||||
@@ -3092,18 +3104,6 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
||||
if(!ftp->no_transfer && !conn->bits.no_body) {
|
||||
/* a transfer is about to take place */
|
||||
|
||||
if(conn->ssl[SECONDARYSOCKET].use &&
|
||||
!data->set.ftp_use_port) {
|
||||
/* PASV is used and we just got the data connection connected, then
|
||||
it is time to handshake the secure stuff. */
|
||||
|
||||
infof(data, "Doing the SSL/TLS handshake on the data stream\n");
|
||||
/* BLOCKING */
|
||||
result = Curl_ssl_connect(conn, SECONDARYSOCKET);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(data->set.upload) {
|
||||
NBFTPSENDF(conn, "TYPE %c", data->set.ftp_ascii?'A':'I');
|
||||
state(conn, FTP_STOR_TYPE);
|
||||
@@ -3811,6 +3811,7 @@ static CURLcode ftp_dophase_done(struct connectdata *conn,
|
||||
/* 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)
|
||||
|
@@ -423,7 +423,11 @@ Curl_addrinfo *Curl_he2ai(struct hostent *he, int port)
|
||||
prevai->ai_next = ai;
|
||||
|
||||
ai->ai_family = AF_INET; /* we only support this */
|
||||
ai->ai_socktype = SOCK_STREAM; /* 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 */
|
||||
|
@@ -202,6 +202,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
struct addrinfo hints, *res;
|
||||
int error;
|
||||
char sbuf[NI_MAXSERV];
|
||||
char *sbufptr = NULL;
|
||||
char addrbuf[128];
|
||||
curl_socket_t s;
|
||||
int pf;
|
||||
@@ -251,10 +252,15 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = pf;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
hints.ai_socktype = conn->socktype;
|
||||
|
||||
hints.ai_flags = ai_flags;
|
||||
snprintf(sbuf, sizeof(sbuf), "%d", port);
|
||||
error = getaddrinfo(hostname, sbuf, &hints, &res);
|
||||
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;
|
||||
|
@@ -88,6 +88,10 @@
|
||||
/* 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
|
||||
**********************************************************************/
|
||||
@@ -289,7 +293,7 @@ static unsigned __stdcall gethostbyname_thread (void *arg)
|
||||
* This allows us to use it even after the container gets destroyed
|
||||
* due to a resolver timeout.
|
||||
*/
|
||||
struct thread_sync_data tsd = {0};
|
||||
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;
|
||||
@@ -356,7 +360,7 @@ static unsigned __stdcall getaddrinfo_thread (void *arg)
|
||||
* This allows us to use it even after the container gets destroyed
|
||||
* due to a resolver timeout.
|
||||
*/
|
||||
struct thread_sync_data tsd = {0};
|
||||
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;
|
||||
@@ -559,7 +563,10 @@ static bool init_resolve_thread (struct connectdata *conn,
|
||||
*/
|
||||
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]), thread_and_event, FALSE, INFINITE) == WAIT_FAILED) {
|
||||
if (WaitForMultipleObjects(sizeof(thread_and_event) /
|
||||
sizeof(thread_and_event[0]),
|
||||
thread_and_event, FALSE,
|
||||
INFINITE) == WAIT_FAILED) {
|
||||
/* The resolver thread has been created,
|
||||
* most probably it works now - ignoring this "minor" error
|
||||
*/
|
||||
@@ -804,7 +811,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = pf;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_socktype = conn->socktype;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
itoa(port, sbuf, 10);
|
||||
|
||||
|
@@ -387,6 +387,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
ULONG attrs;
|
||||
const char *user;
|
||||
int domlen;
|
||||
TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
|
||||
|
||||
ntlm_sspi_cleanup(ntlm);
|
||||
|
||||
@@ -430,8 +431,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
|
||||
if (AcquireCredentialsHandle(
|
||||
NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
|
||||
NULL, NULL, &ntlm->handle, NULL
|
||||
) != SEC_E_OK) {
|
||||
NULL, NULL, &ntlm->handle, &tsDummy
|
||||
) != SEC_E_OK) {
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@@ -447,12 +448,23 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONNECTION,
|
||||
0, SECURITY_NETWORK_DREP, NULL, 0,
|
||||
&ntlm->c_handle, &desc, &attrs, NULL
|
||||
);
|
||||
&ntlm->c_handle, &desc, &attrs, &tsDummy
|
||||
);
|
||||
|
||||
if (status == SEC_I_COMPLETE_AND_CONTINUE ||
|
||||
status == SEC_I_CONTINUE_NEEDED) {
|
||||
CompleteAuthToken(&ntlm->c_handle, &desc);
|
||||
/* CompleteAuthToken() is not present in Win9x, so load it dynamically */
|
||||
SECURITY_STATUS (__stdcall * pCompleteAuthToken)
|
||||
(PCtxtHandle,PSecBufferDesc);
|
||||
HMODULE hSecur32 = GetModuleHandle("secur32.dll");
|
||||
if (hSecur32 != NULL) {
|
||||
pCompleteAuthToken =
|
||||
(SECURITY_STATUS (__stdcall *)(PCtxtHandle,PSecBufferDesc))
|
||||
GetProcAddress(hSecur32, "CompleteAuthToken");
|
||||
if( pCompleteAuthToken != NULL ) {
|
||||
pCompleteAuthToken(&ntlm->c_handle, &desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (status != SEC_E_OK) {
|
||||
FreeCredentialsHandle(&ntlm->handle);
|
||||
@@ -553,6 +565,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
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;
|
||||
@@ -573,7 +586,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
ISC_REQ_CONNECTION,
|
||||
0, SECURITY_NETWORK_DREP, &type_2_desc,
|
||||
0, &ntlm->c_handle, &type_3_desc,
|
||||
&attrs, NULL);
|
||||
&attrs, &tsDummy);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
return CURLE_RECV_ERROR;
|
||||
@@ -700,6 +713,13 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
size=64;
|
||||
ntlmbuf[62]=ntlmbuf[63]=0;
|
||||
|
||||
/* Make sure that the user and domain strings fit in the target buffer
|
||||
before we copy them there. */
|
||||
if(size + userlen + domlen >= sizeof(ntlmbuf)) {
|
||||
failf(conn->data, "user + domain name too big");
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(&ntlmbuf[size], domain, domlen);
|
||||
size += domlen;
|
||||
|
||||
|
@@ -130,8 +130,8 @@ static const struct tzinfo tz[]= {
|
||||
{"CET", -60}, /* Central European */
|
||||
{"MET", -60}, /* Middle European */
|
||||
{"MEWT", -60}, /* Middle European Winter */
|
||||
{"MEST", -120 tDAYZONE}, /* Middle European Summer */
|
||||
{"CEST", -120 tDAYZONE}, /* Central European Summer */
|
||||
{"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 */
|
||||
|
@@ -262,6 +262,14 @@ typedef int curl_socket_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where
|
||||
_beginthreadex() is not available */
|
||||
#if defined(_MSC_VER) && !defined(_MT) && !defined(USE_ARES)
|
||||
#undef USE_THREADING_GETADDRINFO
|
||||
#undef USE_THREADING_GETHOSTBYNAME
|
||||
#define CURL_NO__BEGINTHREADEX
|
||||
#endif
|
||||
|
||||
#ifdef mpeix
|
||||
#define IOCTL_3_ARGS
|
||||
#endif
|
||||
|
@@ -245,6 +245,27 @@ curl_easy_strerror(CURLcode error)
|
||||
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_URL_MALFORMAT_USER: /* not used by current libcurl */
|
||||
case CURLE_MALFORMAT_USER: /* not used by current libcurl */
|
||||
case CURLE_BAD_CALLING_ORDER: /* not used by current libcurl */
|
||||
|
719
lib/tftp.c
Normal file
719
lib/tftp.c
Normal file
@@ -0,0 +1,719 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <time.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#include "urldata.h"
|
||||
#include <curl/curl.h>
|
||||
#include "transfer.h"
|
||||
#include "sendf.h"
|
||||
#include "tftp.h"
|
||||
#include "progress.h"
|
||||
#include "connect.h"
|
||||
#include "strerror.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "select.h"
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifndef MSG_NOSIGNAL
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
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 short event;
|
||||
union {
|
||||
struct {
|
||||
unsigned char data[512];
|
||||
} request;
|
||||
struct {
|
||||
unsigned short block;
|
||||
unsigned char data[512];
|
||||
} data;
|
||||
struct {
|
||||
unsigned short block;
|
||||
} ack;
|
||||
struct {
|
||||
unsigned short code;
|
||||
unsigned char data[512];
|
||||
} error;
|
||||
} u;
|
||||
} 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 sockaddr local_addr;
|
||||
socklen_t local_addrlen;
|
||||
struct sockaddr 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 void tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
|
||||
static void 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 = timeout/5;
|
||||
|
||||
/* Compute the re-start interval to suit the timeout */
|
||||
state->retry_time = timeout/state->retry_max;
|
||||
if(state->retry_time<1) state->retry_time=1;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
/* Compute drop-dead time */
|
||||
maxtime = 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 = 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 = 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 tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
|
||||
{
|
||||
int sbytes;
|
||||
const char *mode = "octet";
|
||||
char *filename = state->conn->path;
|
||||
struct SessionHandle *data = state->conn->data;
|
||||
|
||||
/* Set ascii mode if -B flag was used */
|
||||
if(data->set.ftp_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;
|
||||
}
|
||||
|
||||
if(data->set.upload) {
|
||||
/* If we are uploading, send an WRQ */
|
||||
state->spacket.event = htons(TFTP_EVENT_WRQ);
|
||||
filename = curl_unescape(filename, strlen(filename));
|
||||
state->conn->upload_fromhere = (char *)state->spacket.u.data.data;
|
||||
if(data->set.infilesize != -1) {
|
||||
Curl_pgrsSetUploadSize(data, data->set.infilesize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* If we are downloading, send an RRQ */
|
||||
state->spacket.event = htons(TFTP_EVENT_RRQ);
|
||||
}
|
||||
sprintf((char *)state->spacket.u.request.data, "%s%c%s%c",
|
||||
filename, '\0', mode, '\0');
|
||||
sbytes = 4 + strlen(filename) + strlen(mode);
|
||||
sbytes = sendto(state->sockfd, &state->spacket, sbytes, 0,
|
||||
state->conn->ip_addr->ai_addr,
|
||||
state->conn->ip_addr->ai_addrlen);
|
||||
if(sbytes < 0) {
|
||||
failf(data, "%s\n", strerror(errno));
|
||||
}
|
||||
break;
|
||||
|
||||
case TFTP_EVENT_ACK: /* Connected for transmit */
|
||||
infof(data, "%s\n", "Connected for transmit");
|
||||
state->state = TFTP_STATE_TX;
|
||||
tftp_set_timeouts(state);
|
||||
tftp_tx(state, event);
|
||||
break;
|
||||
|
||||
case TFTP_EVENT_DATA: /* connected for receive */
|
||||
infof(data, "%s\n", "Connected for receive");
|
||||
state->state = TFTP_STATE_RX;
|
||||
tftp_set_timeouts(state);
|
||||
tftp_rx(state, event);
|
||||
break;
|
||||
|
||||
case TFTP_EVENT_ERROR:
|
||||
state->state = TFTP_STATE_FIN;
|
||||
break;
|
||||
|
||||
default:
|
||||
failf(state->conn->data, "tftp_send_first: internal error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
*
|
||||
* tftp_rx
|
||||
*
|
||||
* Event handler for the RX state
|
||||
*
|
||||
**********************************************************/
|
||||
static void 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 = ntohs(state->rpacket.u.data.block);
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* This is the expected block. Reset counters and ACK it. */
|
||||
state->block = rblock;
|
||||
state->retries = 0;
|
||||
state->spacket.event = htons(TFTP_EVENT_ACK);
|
||||
state->spacket.u.ack.block = htons(state->block);
|
||||
sbytes = sendto(state->sockfd, &state->spacket, 4, MSG_NOSIGNAL,
|
||||
&state->remote_addr, state->remote_addrlen);
|
||||
if(sbytes < 0) {
|
||||
failf(data, "%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/* Check if completed (That is, a less than full packet is recieved) */
|
||||
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, &state->spacket,
|
||||
4, MSG_NOSIGNAL,
|
||||
&state->remote_addr, state->remote_addrlen);
|
||||
/* Check all sbytes were sent */
|
||||
if(sbytes<0) {
|
||||
failf(data, "%s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
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*512);
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
*
|
||||
* tftp_tx
|
||||
*
|
||||
* Event handler for the TX state
|
||||
*
|
||||
**********************************************************/
|
||||
static void tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
||||
{
|
||||
struct SessionHandle *data = state->conn->data;
|
||||
int sbytes;
|
||||
int rblock;
|
||||
|
||||
switch(event) {
|
||||
|
||||
case TFTP_EVENT_ACK:
|
||||
/* Ack the packet */
|
||||
rblock = ntohs(state->rpacket.u.data.block);
|
||||
|
||||
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, "%s\n",
|
||||
"tftp_tx: giving up waiting for block %d ack",
|
||||
state->block);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* This is the expected packet. Reset the counters and send the next
|
||||
block */
|
||||
state->block++;
|
||||
state->retries = 0;
|
||||
state->spacket.event = htons(TFTP_EVENT_DATA);
|
||||
state->spacket.u.ack.block = htons(state->block);
|
||||
if(state->block > 1 && state->sbytes < 512) {
|
||||
state->state = TFTP_STATE_FIN;
|
||||
return;
|
||||
}
|
||||
Curl_fillreadbuffer(state->conn, 512, &state->sbytes);
|
||||
sbytes = sendto(state->sockfd, &state->spacket,
|
||||
4+state->sbytes, MSG_NOSIGNAL,
|
||||
&state->remote_addr, state->remote_addrlen);
|
||||
/* Check all sbytes were sent */
|
||||
if(sbytes<0) {
|
||||
failf(data, "%s\n", strerror(errno));
|
||||
}
|
||||
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, &state->spacket,
|
||||
4+state->sbytes, MSG_NOSIGNAL,
|
||||
&state->remote_addr, state->remote_addrlen);
|
||||
/* Check all sbytes were sent */
|
||||
if(sbytes<0) {
|
||||
failf(data, "%s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
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*512);
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
*
|
||||
* tftp_state_machine
|
||||
*
|
||||
* The tftp state machine event dispatcher
|
||||
*
|
||||
**********************************************************/
|
||||
static CURLcode tftp_state_machine(tftp_state_data_t *state,
|
||||
tftp_event_t event)
|
||||
{
|
||||
struct SessionHandle *data = state->conn->data;
|
||||
switch(state->state) {
|
||||
case TFTP_STATE_START:
|
||||
DEBUGF(infof(data, "TFTP_STATE_START\n"));
|
||||
tftp_send_first(state, event);
|
||||
break;
|
||||
case TFTP_STATE_RX:
|
||||
DEBUGF(infof(data, "TFTP_STATE_RX\n"));
|
||||
tftp_rx(state, event);
|
||||
break;
|
||||
case TFTP_STATE_TX:
|
||||
DEBUGF(infof(data, "TFTP_STATE_TX\n"));
|
||||
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");
|
||||
break;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************
|
||||
*
|
||||
* Curl_tftp_connect
|
||||
*
|
||||
* The connect callback
|
||||
*
|
||||
**********************************************************/
|
||||
CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done)
|
||||
{
|
||||
CURLcode code;
|
||||
tftp_state_data_t *state;
|
||||
int rc;
|
||||
|
||||
if((state = conn->proto.tftp = calloc(sizeof(tftp_state_data_t), 1))==NULL) {
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
state->conn = conn;
|
||||
state->sockfd = state->conn->sock[FIRSTSOCKET];
|
||||
state->state = TFTP_STATE_START;
|
||||
|
||||
#ifdef WIN32
|
||||
/* AF_UNSPEC == 0 (from above calloc) doesn't work on Winsock */
|
||||
state->local_addr.sa_family = conn->ip_addr->ai_family;
|
||||
#endif
|
||||
|
||||
tftp_set_timeouts(state);
|
||||
|
||||
/* Bind to any interface, random UDP port */
|
||||
rc = bind(state->sockfd, &state->local_addr, sizeof(state->local_addr));
|
||||
if(rc) {
|
||||
failf(conn->data, "bind() failed; %s\n",
|
||||
Curl_strerror(conn,Curl_ourerrno()));
|
||||
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)
|
||||
{
|
||||
(void)status; /* unused */
|
||||
|
||||
free(conn->proto.tftp);
|
||||
conn->proto.tftp = NULL;
|
||||
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->proto.tftp);
|
||||
tftp_event_t event;
|
||||
CURLcode code;
|
||||
int rc;
|
||||
struct sockaddr fromaddr;
|
||||
socklen_t fromlen;
|
||||
int check_time = 0;
|
||||
|
||||
(void)done; /* prevent compiler warning */
|
||||
|
||||
/* 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_ourerrno();
|
||||
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, &fromaddr, &fromlen);
|
||||
if(state->remote_addrlen==0) {
|
||||
memcpy(&state->remote_addr, &fromaddr, fromlen);
|
||||
state->remote_addrlen = fromlen;
|
||||
}
|
||||
|
||||
/* The event is given by the TFTP packet time */
|
||||
event = (tftp_event_t)ntohs(state->rpacket.event);
|
||||
|
||||
switch(event) {
|
||||
case TFTP_EVENT_DATA:
|
||||
Curl_client_write(data, CLIENTWRITE_BODY,
|
||||
(char *)state->rpacket.u.data.data, state->rbytes-4);
|
||||
break;
|
||||
case TFTP_EVENT_ERROR:
|
||||
state->error = (tftp_error_t)ntohs(state->rpacket.u.error.code);
|
||||
infof(conn->data, "%s\n", (char *)state->rpacket.u.error.data);
|
||||
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 */
|
||||
Curl_pgrsUpdate(conn);
|
||||
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||
|
||||
/* 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
|
31
lib/tftp.h
Normal file
31
lib/tftp.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __TFTP_H
|
||||
#define __TFTP_H
|
||||
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at 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);
|
||||
#endif
|
||||
#endif
|
@@ -880,11 +880,11 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
/* Content-Range: bytes [num]-
|
||||
Content-Range: bytes: [num]-
|
||||
|
||||
The second format was added August 1st 2000 by Igor
|
||||
Khristophorov since Sun's webserver JavaWebServer/1.1.1
|
||||
obviously sends the header this way! :-( */
|
||||
The second format was added since Sun's webserver
|
||||
JavaWebServer/1.1.1 obviously sends the header this way!
|
||||
*/
|
||||
|
||||
char *ptr = strstr(k->p, "bytes");
|
||||
char *ptr = Curl_strcasestr(k->p, "bytes");
|
||||
ptr+=5;
|
||||
|
||||
if(*ptr == ':')
|
||||
@@ -1622,9 +1622,11 @@ Transfer(struct connectdata *conn)
|
||||
CURLcode Curl_pretransfer(struct SessionHandle *data)
|
||||
{
|
||||
CURLcode res;
|
||||
if(!data->change.url)
|
||||
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
|
||||
|
56
lib/url.c
56
lib/url.c
@@ -77,9 +77,7 @@
|
||||
#error "We can't compile without socket() support!"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIBIDN
|
||||
#include <idna.h>
|
||||
#include <tld.h>
|
||||
@@ -123,6 +121,7 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by
|
||||
#include "ftp.h"
|
||||
#include "dict.h"
|
||||
#include "telnet.h"
|
||||
#include "tftp.h"
|
||||
#include "http.h"
|
||||
#include "file.h"
|
||||
#include "ldap.h"
|
||||
@@ -966,6 +965,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
data->set.ftp_use_epsv = va_arg(param, long)?TRUE:FALSE;
|
||||
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)va_arg(param, long);
|
||||
break;
|
||||
|
||||
case CURLOPT_INFILE:
|
||||
/*
|
||||
* FILE pointer to read the file to be uploaded from. Or possibly
|
||||
@@ -1241,7 +1248,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
/*
|
||||
* Set a SSL_CTX callback
|
||||
*/
|
||||
data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
|
||||
data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
|
||||
break;
|
||||
case CURLOPT_SSL_CTX_DATA:
|
||||
/*
|
||||
@@ -1994,7 +2001,8 @@ static CURLcode ConnectPlease(struct connectdata *conn,
|
||||
struct SessionHandle *data = conn->data;
|
||||
char *hostname = data->change.proxy?conn->proxy.name:conn->host.name;
|
||||
|
||||
infof(data, "About to connect() to %s port %d\n",
|
||||
infof(data, "About to connect() to %s%s port %d\n",
|
||||
data->change.proxy?"proxy ":"",
|
||||
hostname, conn->port);
|
||||
|
||||
/*************************************************************
|
||||
@@ -2722,6 +2730,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
* 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;
|
||||
@@ -2915,6 +2925,44 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
#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=<typecode>" that
|
||||
* we'll try to get now! */
|
||||
type=strstr(conn->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 = toupper((int)type[6]);
|
||||
switch(command) {
|
||||
case 'A': /* ASCII mode */
|
||||
case 'N': /* NETASCII mode */
|
||||
data->set.ftp_ascii = 1;
|
||||
break;
|
||||
case 'O': /* octet mode */
|
||||
case 'I': /* binary mode */
|
||||
default:
|
||||
/* switch off ASCII */
|
||||
data->set.ftp_ascii = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
failf(data, LIBCURL_NAME
|
||||
" was built with TFTP disabled!");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#define PORT_HTTPS 443
|
||||
#define PORT_DICT 2628
|
||||
#define PORT_LDAP 389
|
||||
#define PORT_TFTP 69
|
||||
|
||||
#define DICT_MATCH "/MATCH:"
|
||||
#define DICT_MATCH2 "/M:"
|
||||
@@ -540,6 +541,7 @@ struct connectdata {
|
||||
#define PROT_DICT (1<<6)
|
||||
#define PROT_LDAP (1<<7)
|
||||
#define PROT_FILE (1<<8)
|
||||
#define PROT_TFTP (1<<11)
|
||||
#define PROT_FTPS (1<<9)
|
||||
#define PROT_SSL (1<<10) /* protocol requires SSL */
|
||||
|
||||
@@ -560,6 +562,7 @@ struct connectdata {
|
||||
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;
|
||||
@@ -695,6 +698,7 @@ struct connectdata {
|
||||
struct HTTP *gopher; /* alias, just for the sake of being more readable */
|
||||
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;
|
||||
@@ -1069,8 +1073,9 @@ struct UserDefined {
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -81,6 +81,9 @@ char *curl_version(void)
|
||||
/* data for curl_version_info */
|
||||
|
||||
static const char * const protocols[] = {
|
||||
#ifndef CURL_DISABLE_TFTP
|
||||
"tftp",
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
"ftp",
|
||||
#endif
|
||||
|
1
maketgz
1
maketgz
@@ -25,7 +25,6 @@ CHEADER=src/version.h
|
||||
|
||||
# Replace version number in header file:
|
||||
sed -e 's/^#define LIBCURL_VERSION .*/#define LIBCURL_VERSION "'$libversion'"/g' \
|
||||
-e 's/^#define LIBCURL_VERSION_NUM .*/#define LIBCURL_VERSION_NUM 0x'$numeric'/g' \
|
||||
-e 's/^#define LIBCURL_VERSION_MAJOR .*/#define LIBCURL_VERSION_MAJOR '$major'/g' \
|
||||
-e 's/^#define LIBCURL_VERSION_MINOR .*/#define LIBCURL_VERSION_MINOR '$minor'/g' \
|
||||
-e 's/^#define LIBCURL_VERSION_PATCH .*/#define LIBCURL_VERSION_PATCH '$patch'/g' \
|
||||
|
@@ -283,7 +283,7 @@ config.h: Makefile.netware
|
||||
@echo $(DL)*/$(DL) >> $@
|
||||
@echo $(DL)#define OS "i586-pc-NetWare"$(DL) >> $@
|
||||
@echo $(DL)#define VERSION "$(LIBCURL_VERSION_STR)"$(DL) >> $@
|
||||
@echo $(DL)#define PACKAGE_BUGREPORT "curl-bug@haxx.se"$(DL) >> $@
|
||||
@echo $(DL)#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"$(DL) >> $@
|
||||
@echo $(DL)#define USE_MANUAL 1$(DL) >> $@
|
||||
@echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@
|
||||
@echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@
|
||||
|
18
src/main.c
18
src/main.c
@@ -315,6 +315,7 @@ struct Configurable {
|
||||
bool insecure_ok; /* set TRUE to allow insecure SSL connects */
|
||||
bool create_dirs;
|
||||
bool ftp_create_dirs;
|
||||
bool ftp_skip_ip;
|
||||
bool proxyntlm;
|
||||
bool proxydigest;
|
||||
bool proxybasic;
|
||||
@@ -508,7 +509,8 @@ static void help(void)
|
||||
" --crlf Convert LF to CRLF in upload",
|
||||
" -f/--fail Fail silently (no output at all) on errors (H)",
|
||||
" --ftp-create-dirs Create the remote dirs if not present (F)",
|
||||
" --ftp-pasv Use PASV instead of PORT (F)",
|
||||
" --ftp-pasv Use PASV/EPSV instead of PORT (F)",
|
||||
" --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
|
||||
" --ftp-ssl Enable SSL/TLS for the ftp transfer (F)",
|
||||
" -F/--form <name=content> Specify HTTP multipart POST data (H)",
|
||||
" --form-string <name=string> Specify HTTP multipart POST data (H)",
|
||||
@@ -1313,6 +1315,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
{"$n", "proxy-anyauth", FALSE},
|
||||
{"$o", "trace-time", FALSE},
|
||||
{"$p", "ignore-content-length", FALSE},
|
||||
{"$q", "ftp-skip-pasv-ip", FALSE},
|
||||
|
||||
{"0", "http1.0", FALSE},
|
||||
{"1", "tlsv1", FALSE},
|
||||
@@ -1709,6 +1712,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
case 'p': /* --ignore-content-length */
|
||||
config->ignorecl ^= TRUE;
|
||||
break;
|
||||
case 'q': /* --ftp-skip-pasv-ip */
|
||||
config->ftp_skip_ip ^= TRUE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '#': /* --progress-bar */
|
||||
@@ -3905,6 +3911,10 @@ operate(struct Configurable *config, int argc, char *argv[])
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
|
||||
|
||||
/* curl 7.14.2 */
|
||||
curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP,
|
||||
config->ftp_skip_ip);
|
||||
|
||||
retry_numretries = config->req_retry;
|
||||
|
||||
retrystart = curlx_tvnow();
|
||||
@@ -4149,15 +4159,15 @@ quit_curl:
|
||||
if (config->engine)
|
||||
free(config->engine);
|
||||
|
||||
/* cleanup the curl handle! */
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if(config->headerfile && !headerfilep && heads.stream)
|
||||
fclose(heads.stream);
|
||||
|
||||
if(allocuseragent)
|
||||
free(config->useragent);
|
||||
|
||||
/* cleanup the curl handle! */
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if(config->trace_fopened && config->trace_stream)
|
||||
fclose(config->trace_stream);
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -112,11 +112,13 @@ void ourWriteOut(CURL *curl, char *writeinfo)
|
||||
char keepit;
|
||||
int i;
|
||||
if(('{' == ptr[1]) && (end=strchr(ptr, '}'))) {
|
||||
bool match = FALSE;
|
||||
ptr+=2; /* pass the % and the { */
|
||||
keepit=*end;
|
||||
*end=0; /* zero terminate */
|
||||
for(i=0; replacements[i].name; i++) {
|
||||
if(curl_strequal(ptr, replacements[i].name)) {
|
||||
match = TRUE;
|
||||
switch(replacements[i].id) {
|
||||
case VAR_EFFECTIVE_URL:
|
||||
if((CURLE_OK ==
|
||||
@@ -217,6 +219,9 @@ void ourWriteOut(CURL *curl, char *writeinfo)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!match) {
|
||||
fprintf(stderr, "curl: unknown --writeout variable: '%s'\n", ptr);
|
||||
}
|
||||
ptr=end+1; /* pass the end */
|
||||
*end = keepit;
|
||||
}
|
||||
|
@@ -81,6 +81,7 @@ RETRWEIRDO
|
||||
RETRNOSIZE
|
||||
NOSAVE
|
||||
SLOWDOWN
|
||||
PASVBADIP - makes PASV send back an illegal IP in its 227 response
|
||||
|
||||
For HTTP, one specified command is supported:
|
||||
"auth_required" - if this is set and a POST/PUT is made without auth, the
|
||||
|
@@ -33,4 +33,4 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
|
||||
test237 test238 test239 test243 test245 test246 test247 test248 test249 \
|
||||
test250 test251 test252 test253 test254 test255 test521 test522 test523 \
|
||||
test256 test257 test258 test259 test260 test261 test262 test263 test264 \
|
||||
test265 test266 test267 test268 test269
|
||||
test265 test266 test267 test268 test269 test270 test271 test272
|
||||
|
48
tests/data/test270
Normal file
48
tests/data/test270
Normal file
@@ -0,0 +1,48 @@
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
data
|
||||
to
|
||||
see
|
||||
that FTP
|
||||
works
|
||||
so does it?
|
||||
</data>
|
||||
<servercmd>
|
||||
PASVBADIP
|
||||
</servercmd>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP RETR PASV --ftp-skip-pasv-ip
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT/270 --ftp-skip-pasv-ip --disable-epsv
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
USER anonymous
|
||||
PASS curl_by_daniel@haxx.se
|
||||
PWD
|
||||
PASV
|
||||
TYPE I
|
||||
SIZE 270
|
||||
RETR 270
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
41
tests/data/test271
Normal file
41
tests/data/test271
Normal file
@@ -0,0 +1,41 @@
|
||||
<info>
|
||||
<keywords>
|
||||
TFTP
|
||||
TFTP RRQ
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
<data>
|
||||
a chunk of
|
||||
data
|
||||
returned
|
||||
to client
|
||||
</data>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
tftp
|
||||
</server>
|
||||
<name>
|
||||
TFTP retrieve
|
||||
</name>
|
||||
<command>
|
||||
tftp://%HOSTIP:%TFTPPORT/271 --trace-ascii log/traceit
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify pseudo protocol after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
opcode: 1
|
||||
filename: /271
|
||||
mode: octet
|
||||
</protocol>
|
||||
</verify>
|
38
tests/data/test272
Normal file
38
tests/data/test272
Normal file
@@ -0,0 +1,38 @@
|
||||
<info>
|
||||
<keywords>
|
||||
FTP
|
||||
PASV
|
||||
RETR
|
||||
</keywords>
|
||||
</info>
|
||||
# Server-side
|
||||
<reply>
|
||||
<mdtm>
|
||||
213 20040101121212
|
||||
</mdtm>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
ftp
|
||||
</server>
|
||||
<name>
|
||||
FTP timed conditioned get file with identical time stamp
|
||||
</name>
|
||||
<command>
|
||||
ftp://%HOSTIP:%FTPPORT/272 -z "2004 jan 1 12:12:12 UTC"
|
||||
</command>
|
||||
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
USER anonymous
|
||||
PASS curl_by_daniel@haxx.se
|
||||
PWD
|
||||
MDTM 272
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
@@ -70,6 +70,7 @@ sub ftpmsg {
|
||||
}
|
||||
|
||||
my $verbose=0; # set to 1 for debugging
|
||||
my $pasvbadip=0;
|
||||
my $retrweirdo=0;
|
||||
my $retrnosize=0;
|
||||
my $srcdir=".";
|
||||
@@ -564,7 +565,11 @@ sub PASV_command {
|
||||
|
||||
if($cmd ne "EPSV") {
|
||||
# PASV reply
|
||||
sendcontrol sprintf("227 Entering Passive Mode (127,0,0,1,%d,%d)\n",
|
||||
my $p="127,0,0,1";
|
||||
if($pasvbadip) {
|
||||
$p="1,2,3,4";
|
||||
}
|
||||
sendcontrol sprintf("227 Entering Passive Mode ($p,%d,%d)\n",
|
||||
($pasvport/256), ($pasvport%256));
|
||||
}
|
||||
else {
|
||||
@@ -703,6 +708,10 @@ sub customize {
|
||||
logmsg "FTPD: instructed to use RETRNOSIZE\n";
|
||||
$retrnosize=1;
|
||||
}
|
||||
elsif($_ =~ /PASVBADIP/) {
|
||||
logmsg "FTPD: instructed to use PASVBADIP\n";
|
||||
$pasvbadip=1;
|
||||
}
|
||||
elsif($_ =~ /NOSAVE/) {
|
||||
# don't actually store the file we upload - to be used when
|
||||
# uploading insanely huge amounts
|
||||
|
@@ -46,6 +46,8 @@ my $FTPPORT; # FTP server port
|
||||
my $FTP2PORT; # FTP server 2 port
|
||||
my $FTPSPORT; # FTPS server port
|
||||
my $FTP6PORT; # FTP IPv6 server port
|
||||
my $TFTPPORT; # TFTP
|
||||
my $TFTP6PORT; # TFTP
|
||||
|
||||
my $CURL="../src/curl"; # what curl executable to run on the tests
|
||||
my $DBGCURL=$CURL; #"../src/.libs/curl"; # alternative for debugging
|
||||
@@ -75,6 +77,8 @@ my $FTPPIDFILE=".ftp.pid";
|
||||
my $FTP6PIDFILE=".ftp6.pid";
|
||||
my $FTP2PIDFILE=".ftp2.pid";
|
||||
my $FTPSPIDFILE=".ftps.pid";
|
||||
my $TFTPPIDFILE=".tftpd.pid";
|
||||
my $TFTP6PIDFILE=".tftp6.pid";
|
||||
|
||||
# invoke perl like this:
|
||||
my $perl="perl -I$srcdir";
|
||||
@@ -128,6 +132,7 @@ my $large_file; # set if libcurl is built with large file support
|
||||
my $has_idn; # set if libcurl is built with IDN support
|
||||
my $http_ipv6; # set if HTTP server has IPv6 support
|
||||
my $ftp_ipv6; # set if FTP server has IPv6 support
|
||||
my $tftp_ipv6; # set if TFTP server has IPv6 support
|
||||
my $has_ipv6; # set if libcurl is built with IPv6 support
|
||||
my $has_libz; # set if libcurl is built with libz support
|
||||
my $has_getrlimit; # set if system has getrlimit()
|
||||
@@ -489,7 +494,8 @@ sub verifyftp {
|
||||
|
||||
my %protofunc = ('http' => \&verifyhttp,
|
||||
'https' => \&verifyhttp,
|
||||
'ftp' => \&verifyftp);
|
||||
'ftp' => \&verifyftp,
|
||||
'tftp' => \&verifyftp);
|
||||
|
||||
sub verifyserver {
|
||||
my ($proto, $ip, $port) = @_;
|
||||
@@ -691,6 +697,72 @@ sub runftpserver {
|
||||
return ($pid2, $ftppid);
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# start the tftp server
|
||||
#
|
||||
sub runtftpserver {
|
||||
my ($id, $verbose, $ipv6) = @_;
|
||||
my $STATUS;
|
||||
my $RUNNING;
|
||||
my $port = $TFTPPORT;
|
||||
# check for pidfile
|
||||
my $pidfile = $TFTPPIDFILE;
|
||||
my $ip=$HOSTIP;
|
||||
my $nameext;
|
||||
my $cmd;
|
||||
|
||||
if($ipv6) {
|
||||
# if IPv6, use a different setup
|
||||
$pidfile = $TFTP6PIDFILE;
|
||||
$port = $TFTP6PORT;
|
||||
$ip = $HOST6IP;
|
||||
$nameext="-ipv6";
|
||||
}
|
||||
|
||||
my $pid = checkserver($pidfile);
|
||||
if($pid >= 0) {
|
||||
stopserver($pid);
|
||||
}
|
||||
|
||||
# start our server:
|
||||
my $flag=$debugprotocol?"-v ":"";
|
||||
$flag .= "-s \"$srcdir\" ";
|
||||
if($id) {
|
||||
$flag .="--id $id ";
|
||||
}
|
||||
if($ipv6) {
|
||||
$flag .="--ipv6 ";
|
||||
}
|
||||
$cmd="./server/tftpd --pidfile $pidfile $flag $port";
|
||||
|
||||
unlink($pidfile);
|
||||
|
||||
my ($tftppid, $pid2) = startnew($cmd, $pidfile);
|
||||
|
||||
if(!$tftppid || !kill(0, $tftppid)) {
|
||||
# it is NOT alive
|
||||
logmsg "RUN: failed to start the FTP$id$nameext server!\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
# Server is up. Verify that we can speak to it.
|
||||
if(!verifyserver("tftp", $ip, $port)) {
|
||||
logmsg "RUN: TFTP$id$nameext server failed verification\n";
|
||||
# failed to talk to it properly. Kill the server and return failure
|
||||
stopserver("$tftppid $pid2");
|
||||
return (0,0);
|
||||
}
|
||||
|
||||
if($verbose) {
|
||||
logmsg "RUN: TFTP$id$nameext server is now running PID $tftppid\n";
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
return ($pid2, $tftppid);
|
||||
}
|
||||
|
||||
|
||||
#######################################################################
|
||||
# Remove all files in the specified directory
|
||||
#
|
||||
@@ -946,6 +1018,10 @@ sub checksystem {
|
||||
if($ftp_ipv6) {
|
||||
logmsg sprintf("* FTP IPv6 port: %d\n", $FTP6PORT);
|
||||
}
|
||||
logmsg sprintf("* TFTP port: %d\n", $TFTPPORT);
|
||||
if($tftp_ipv6) {
|
||||
logmsg sprintf("* TFTP IPv6 port: %d\n", $TFTP6PORT);
|
||||
}
|
||||
|
||||
if($ssl_version) {
|
||||
logmsg sprintf("* SSL library: %s\n",
|
||||
@@ -974,6 +1050,8 @@ sub subVariables {
|
||||
$$thing =~ s/%FTPSPORT/$FTPSPORT/g;
|
||||
$$thing =~ s/%SRCDIR/$srcdir/g;
|
||||
$$thing =~ s/%PWD/$pwd/g;
|
||||
$$thing =~ s/%TFTPPORT/$TFTPPORT/g;
|
||||
$$thing =~ s/%TFTP6PORT/$TFTP6PORT/g;
|
||||
}
|
||||
|
||||
sub fixarray {
|
||||
@@ -1760,6 +1838,26 @@ sub startservers {
|
||||
$run{'https'}="$pid $pid2";
|
||||
}
|
||||
}
|
||||
elsif($what eq "tftp") {
|
||||
if(!$run{'tftp'}) {
|
||||
($pid, $pid2) = runtftpserver("", $verbose);
|
||||
if($pid <= 0) {
|
||||
return "failed starting TFTP server";
|
||||
}
|
||||
printf ("* pid tftp => %d %d\n", $pid, $pid2) if($verbose);
|
||||
$run{'tftp'}="$pid $pid2";
|
||||
}
|
||||
}
|
||||
elsif($what eq "tftp-ipv6") {
|
||||
if(!$run{'tftp-ipv6'}) {
|
||||
($pid, $pid2) = runtftpserver("", $verbose, "IPv6");
|
||||
if($pid <= 0) {
|
||||
return "failed starting TFTP-IPv6 server";
|
||||
}
|
||||
printf("* pid tftp-ipv6 => %d %d\n", $pid, $pid2) if($verbose);
|
||||
$run{'tftp-ipv6'}="$pid $pid2";
|
||||
}
|
||||
}
|
||||
elsif($what eq "none") {
|
||||
logmsg "* starts no server\n" if ($verbose);
|
||||
}
|
||||
@@ -1920,6 +2018,8 @@ $HTTP6PORT = $base + 4; # HTTP IPv6 server port (different IP protocol
|
||||
# but we follow the same port scheme anyway)
|
||||
$FTP2PORT = $base + 5; # FTP server 2 port
|
||||
$FTP6PORT = $base + 6; # FTP IPv6 port
|
||||
$TFTPPORT = $base + 7; # TFTP (UDP) port
|
||||
$TFTP6PORT = $base + 8; # TFTP IPv6 (UDP) port
|
||||
|
||||
#######################################################################
|
||||
# Output curl version and host info being tested
|
||||
|
@@ -8,3 +8,4 @@ Makefile
|
||||
getpart
|
||||
sockfilt
|
||||
resolve
|
||||
tftpd
|
||||
|
@@ -25,7 +25,7 @@ AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/include
|
||||
|
||||
noinst_PROGRAMS = sws getpart sockfilt resolve
|
||||
noinst_PROGRAMS = sws getpart sockfilt resolve tftpd
|
||||
|
||||
useful = getpart.c getpart.h $(top_srcdir)/lib/strequal.c \
|
||||
$(top_srcdir)/lib/base64.c $(top_srcdir)/lib/mprintf.c \
|
||||
@@ -36,5 +36,7 @@ sws_SOURCES= sws.c util.c util.h $(useful)
|
||||
sockfilt_SOURCES = sockfilt.c util.c util.h $(useful) \
|
||||
$(top_srcdir)/lib/inet_pton.c
|
||||
getpart_SOURCES= testpart.c $(useful)
|
||||
tftpd_SOURCES = tftpd.c util.c util.h $(useful)
|
||||
|
||||
extra_DIST = base64.pl
|
||||
|
||||
|
@@ -105,8 +105,6 @@ const char *serverlogfile = DEFAULT_LOGFILE;
|
||||
#define REQUEST_DUMP "log/server.input"
|
||||
#define RESPONSE_DUMP "log/server.response"
|
||||
|
||||
#define TEST_DATA_PATH "%s/data/test%ld"
|
||||
|
||||
/* very-big-path support */
|
||||
#define MAXDOCNAMELEN 140000
|
||||
#define MAXDOCNAMELEN_TXT "139999"
|
||||
@@ -117,9 +115,6 @@ const char *serverlogfile = DEFAULT_LOGFILE;
|
||||
|
||||
#define END_OF_HEADERS "\r\n\r\n"
|
||||
|
||||
/* global variable, where to find the 'data' dir */
|
||||
const char *path=".";
|
||||
|
||||
enum {
|
||||
DOCNUMBER_NOTHING = -7,
|
||||
DOCNUMBER_QUIT = -6,
|
||||
@@ -169,14 +164,6 @@ static void sigpipe_handler(int sig)
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *test2file(long testno)
|
||||
{
|
||||
static char filename[256];
|
||||
sprintf(filename, TEST_DATA_PATH, path, testno);
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
int ProcessRequest(struct httprequest *req)
|
||||
{
|
||||
char *line=req->reqbuf;
|
||||
@@ -338,7 +325,7 @@ int ProcessRequest(struct httprequest *req)
|
||||
}
|
||||
|
||||
if(chunked) {
|
||||
if(strstr(req->reqbuf, "\r\n0\r\n"))
|
||||
if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
|
||||
/* end of chunks reached */
|
||||
return 1; /* done */
|
||||
else
|
||||
@@ -642,7 +629,8 @@ int main(int argc, char *argv[])
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 me6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
int sock, msgsock, flag;
|
||||
curl_socket_t sock, msgsock;
|
||||
int flag;
|
||||
unsigned short port = DEFAULT_PORT;
|
||||
FILE *pidfile;
|
||||
char *pidname= (char *)".http.pid";
|
||||
|
900
tests/server/tftpd.c
Normal file
900
tests/server/tftpd.c
Normal file
@@ -0,0 +1,900 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Trivial file transfer protocol server.
|
||||
*
|
||||
* This code includes many modifications by Jim Guyton <guyton@rand-unix>
|
||||
*
|
||||
* This source file was started based on netkit-tftpd 0.17
|
||||
* Heavily modified for curl's test suite
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983 Regents of the University of California.
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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" /* portability help from the lib directory */
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_TFTP_H
|
||||
#include <arpa/tftp.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILIO_H
|
||||
/* FIONREAD on Solaris 7 */
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#define ENABLE_CURLX_PRINTF
|
||||
/* make the curlx header define all printf() functions to use the curlx_*
|
||||
versions instead */
|
||||
#include "curlx.h" /* from the private lib dir */
|
||||
#include "getpart.h"
|
||||
#include "util.h"
|
||||
|
||||
/* include memdebug.h last */
|
||||
#include "memdebug.h"
|
||||
|
||||
struct testcase {
|
||||
char *buffer; /* holds the file data to send to the client */
|
||||
size_t bufsize; /* size of the data in buffer */
|
||||
char *rptr; /* read pointer into the buffer */
|
||||
size_t rcount; /* amount of data left to read of the file */
|
||||
long num; /* test case number */
|
||||
int ofile; /* file descriptor for output file when uploading to us */
|
||||
FILE *server; /* write input "protocol" there for client verification */
|
||||
};
|
||||
|
||||
static int synchnet(int);
|
||||
static struct tftphdr *r_init(void);
|
||||
static struct tftphdr *w_init(void);
|
||||
static int readit(struct testcase *test, struct tftphdr **dpp, int convert);
|
||||
static int writeit(struct testcase *test, struct tftphdr **dpp, int ct,
|
||||
int convert);
|
||||
static void mysignal(int, void (*func)(int));
|
||||
|
||||
|
||||
#define TIMEOUT 5
|
||||
|
||||
#define PKTSIZE SEGSIZE+4
|
||||
|
||||
struct formats;
|
||||
static int tftp(struct testcase *test, struct tftphdr *tp, int size);
|
||||
static void nak(int error);
|
||||
static void sendtftp(struct testcase *test, struct formats *pf);
|
||||
static void recvtftp(struct testcase *test, struct formats *pf);
|
||||
static int validate_access(struct testcase *test, const char *, int);
|
||||
|
||||
static curl_socket_t peer;
|
||||
static int rexmtval = TIMEOUT;
|
||||
static int maxtimeout = 5*TIMEOUT;
|
||||
|
||||
static char buf[PKTSIZE];
|
||||
static char ackbuf[PKTSIZE];
|
||||
static struct sockaddr_in from;
|
||||
static socklen_t fromlen;
|
||||
|
||||
struct bf {
|
||||
int counter; /* size of data in buffer, or flag */
|
||||
char buf[PKTSIZE]; /* room for data packet */
|
||||
} bfs[2];
|
||||
|
||||
/* Values for bf.counter */
|
||||
#define BF_ALLOC -3 /* alloc'd but not yet filled */
|
||||
#define BF_FREE -2 /* free */
|
||||
/* [-1 .. SEGSIZE] = size of data in the data buffer */
|
||||
|
||||
static int nextone; /* index of next buffer to use */
|
||||
static int current; /* index of buffer in use */
|
||||
|
||||
/* control flags for crlf conversions */
|
||||
int newline = 0; /* fillbuf: in middle of newline expansion */
|
||||
int prevchar = -1; /* putbuf: previous char (cr check) */
|
||||
|
||||
static void read_ahead(struct testcase *test,
|
||||
int convert /* if true, convert to ascii */);
|
||||
static int write_behind(struct testcase *test, int convert);
|
||||
static struct tftphdr *rw_init(int);
|
||||
static struct tftphdr *w_init(void) { return rw_init(0); } /* write-behind */
|
||||
static struct tftphdr *r_init(void) { return rw_init(1); } /* read-ahead */
|
||||
|
||||
static struct tftphdr *
|
||||
rw_init(int x) /* init for either read-ahead or write-behind */
|
||||
{ /* zero for write-behind, one for read-head */
|
||||
newline = 0; /* init crlf flag */
|
||||
prevchar = -1;
|
||||
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
|
||||
current = 0;
|
||||
bfs[1].counter = BF_FREE;
|
||||
nextone = x; /* ahead or behind? */
|
||||
return (struct tftphdr *)bfs[0].buf;
|
||||
}
|
||||
|
||||
|
||||
/* Have emptied current buffer by sending to net and getting ack.
|
||||
Free it and return next buffer filled with data.
|
||||
*/
|
||||
static int readit(struct testcase *test, struct tftphdr **dpp,
|
||||
int convert /* if true, convert to ascii */)
|
||||
{
|
||||
struct bf *b;
|
||||
|
||||
bfs[current].counter = BF_FREE; /* free old one */
|
||||
current = !current; /* "incr" current */
|
||||
|
||||
b = &bfs[current]; /* look at new buffer */
|
||||
if (b->counter == BF_FREE) /* if it's empty */
|
||||
read_ahead(test, convert); /* fill it */
|
||||
|
||||
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
|
||||
return b->counter;
|
||||
}
|
||||
|
||||
#undef MIN /* some systems have this defined already, some don't */
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y));
|
||||
|
||||
/*
|
||||
* fill the input buffer, doing ascii conversions if requested
|
||||
* conversions are lf -> cr,lf and cr -> cr, nul
|
||||
*/
|
||||
static void read_ahead(struct testcase *test,
|
||||
int convert /* if true, convert to ascii */)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
int c;
|
||||
struct bf *b;
|
||||
struct tftphdr *dp;
|
||||
|
||||
b = &bfs[nextone]; /* look at "next" buffer */
|
||||
if (b->counter != BF_FREE) /* nop if not free */
|
||||
return;
|
||||
nextone = !nextone; /* "incr" next buffer ptr */
|
||||
|
||||
dp = (struct tftphdr *)b->buf;
|
||||
|
||||
if (convert == 0) {
|
||||
/* The former file reading code did this:
|
||||
b->counter = read(fileno(file), dp->th_data, SEGSIZE); */
|
||||
int copy_n = MIN(SEGSIZE, test->rcount);
|
||||
memcpy(dp->th_data, test->rptr, copy_n);
|
||||
|
||||
/* decrease amount, advance pointer */
|
||||
test->rcount -= copy_n;
|
||||
test->rptr += copy_n;
|
||||
b->counter = copy_n;
|
||||
return;
|
||||
}
|
||||
|
||||
p = dp->th_data;
|
||||
for (i = 0 ; i < SEGSIZE; i++) {
|
||||
if (newline) {
|
||||
if (prevchar == '\n')
|
||||
c = '\n'; /* lf to cr,lf */
|
||||
else
|
||||
c = '\0'; /* cr to cr,nul */
|
||||
newline = 0;
|
||||
}
|
||||
else {
|
||||
if(test->rcount) {
|
||||
c=test->rptr[0];
|
||||
test->rptr++;
|
||||
test->rcount--;
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (c == '\n' || c == '\r') {
|
||||
prevchar = c;
|
||||
c = '\r';
|
||||
newline = 1;
|
||||
}
|
||||
}
|
||||
*p++ = c;
|
||||
}
|
||||
b->counter = (int)(p - dp->th_data);
|
||||
}
|
||||
|
||||
/* Update count associated with the buffer, get new buffer from the queue.
|
||||
Calls write_behind only if next buffer not available.
|
||||
*/
|
||||
static int writeit(struct testcase *test, struct tftphdr **dpp,
|
||||
int ct, int convert)
|
||||
{
|
||||
bfs[current].counter = ct; /* set size of data to write */
|
||||
current = !current; /* switch to other buffer */
|
||||
if (bfs[current].counter != BF_FREE) /* if not free */
|
||||
write_behind(test, convert); /* flush it */
|
||||
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
|
||||
*dpp = (struct tftphdr *)bfs[current].buf;
|
||||
return ct; /* this is a lie of course */
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a buffer to a file, converting from netascii if requested.
|
||||
* CR,NUL -> CR and CR,LF => LF.
|
||||
* Note spec is undefined if we get CR as last byte of file or a
|
||||
* CR followed by anything else. In this case we leave it alone.
|
||||
*/
|
||||
static int write_behind(struct testcase *test, int convert)
|
||||
{
|
||||
char *buf;
|
||||
int count;
|
||||
int ct;
|
||||
char *p;
|
||||
int c; /* current character */
|
||||
struct bf *b;
|
||||
struct tftphdr *dp;
|
||||
|
||||
b = &bfs[nextone];
|
||||
if (b->counter < -1) /* anything to flush? */
|
||||
return 0; /* just nop if nothing to do */
|
||||
|
||||
if(!test->ofile) {
|
||||
char outfile[256];
|
||||
snprintf(outfile, sizeof(outfile), "log/upload.%ld", test->num);
|
||||
test->ofile=open(outfile, O_CREAT|O_RDWR, 0777);
|
||||
if(test->ofile == -1) {
|
||||
logmsg("Couldn't create and/or open file %s for upload!", outfile);
|
||||
return -1; /* failure! */
|
||||
}
|
||||
}
|
||||
|
||||
count = b->counter; /* remember byte count */
|
||||
b->counter = BF_FREE; /* reset flag */
|
||||
dp = (struct tftphdr *)b->buf;
|
||||
nextone = !nextone; /* incr for next time */
|
||||
buf = dp->th_data;
|
||||
|
||||
if (count <= 0)
|
||||
return -1; /* nak logic? */
|
||||
|
||||
if (convert == 0)
|
||||
return write(test->ofile, buf, count);
|
||||
|
||||
p = buf;
|
||||
ct = count;
|
||||
while (ct--) { /* loop over the buffer */
|
||||
c = *p++; /* pick up a character */
|
||||
if (prevchar == '\r') { /* if prev char was cr */
|
||||
if (c == '\n') /* if have cr,lf then just */
|
||||
lseek(test->ofile, -1, SEEK_CUR); /* smash lf on top of the cr */
|
||||
else
|
||||
if (c == '\0') /* if have cr,nul then */
|
||||
goto skipit; /* just skip over the putc */
|
||||
/* else just fall through and allow it */
|
||||
}
|
||||
/* formerly
|
||||
putc(c, file); */
|
||||
write(test->ofile, &c, 1);
|
||||
skipit:
|
||||
prevchar = c;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* When an error has occurred, it is possible that the two sides are out of
|
||||
* synch. Ie: that what I think is the other side's response to packet N is
|
||||
* really their response to packet N-1.
|
||||
*
|
||||
* So, to try to prevent that, we flush all the input queued up for us on the
|
||||
* network connection on our host.
|
||||
*
|
||||
* We return the number of packets we flushed (mostly for reporting when trace
|
||||
* is active).
|
||||
*/
|
||||
|
||||
static int synchnet(curl_socket_t f /* socket to flush */)
|
||||
{
|
||||
int i, j = 0;
|
||||
char rbuf[PKTSIZE];
|
||||
struct sockaddr_in from;
|
||||
socklen_t fromlen;
|
||||
|
||||
while (1) {
|
||||
(void) ioctl(f, FIONREAD, &i);
|
||||
if (i) {
|
||||
j++;
|
||||
fromlen = sizeof from;
|
||||
(void) recvfrom(f, rbuf, sizeof (rbuf), 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
}
|
||||
else
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Like signal(), but with well-defined semantics.
|
||||
*/
|
||||
static void mysignal(int sig, void (*handler)(int))
|
||||
{
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = handler;
|
||||
sigaction(sig, &sa, NULL);
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEFAULT_LOGFILE
|
||||
#define DEFAULT_LOGFILE "log/tftpd.log"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PORT 8999 /* UDP */
|
||||
const char *serverlogfile = DEFAULT_LOGFILE;
|
||||
|
||||
#define REQUEST_DUMP "log/server.input"
|
||||
|
||||
char use_ipv6=FALSE;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sockaddr_in me;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 me6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
struct tftphdr *tp;
|
||||
int n = 0;
|
||||
int arg = 1;
|
||||
FILE *pidfile;
|
||||
char *pidname= (char *)".tftpd.pid";
|
||||
unsigned short port = DEFAULT_PORT;
|
||||
curl_socket_t sock;
|
||||
int flag;
|
||||
int rc;
|
||||
struct testcase test;
|
||||
|
||||
while(argc>arg) {
|
||||
if(!strcmp("--version", argv[arg])) {
|
||||
printf("tftpd IPv4%s\n",
|
||||
#ifdef ENABLE_IPV6
|
||||
"/IPv6"
|
||||
#else
|
||||
""
|
||||
#endif
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
else if(!strcmp("--pidfile", argv[arg])) {
|
||||
arg++;
|
||||
if(argc>arg)
|
||||
pidname = argv[arg++];
|
||||
}
|
||||
else if(!strcmp("--ipv6", argv[arg])) {
|
||||
#ifdef ENABLE_IPV6
|
||||
use_ipv6=TRUE;
|
||||
#endif
|
||||
arg++;
|
||||
}
|
||||
else if(argc>arg) {
|
||||
|
||||
if(atoi(argv[arg]))
|
||||
port = (unsigned short)atoi(argv[arg++]);
|
||||
|
||||
if(argc>arg)
|
||||
path = argv[arg++];
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
|
||||
win32_init();
|
||||
atexit(win32_cleanup);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if(!use_ipv6)
|
||||
#endif
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
#ifdef ENABLE_IPV6
|
||||
else
|
||||
sock = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
|
||||
if (sock < 0) {
|
||||
perror("opening stream socket");
|
||||
logmsg("Error opening socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
flag = 1;
|
||||
if (setsockopt
|
||||
(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag,
|
||||
sizeof(int)) < 0) {
|
||||
perror("setsockopt(SO_REUSEADDR)");
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
if(!use_ipv6) {
|
||||
#endif
|
||||
me.sin_family = AF_INET;
|
||||
me.sin_addr.s_addr = INADDR_ANY;
|
||||
me.sin_port = htons(port);
|
||||
rc = bind(sock, (struct sockaddr *) &me, sizeof(me));
|
||||
#ifdef ENABLE_IPV6
|
||||
}
|
||||
else {
|
||||
memset(&me6, 0, sizeof(struct sockaddr_in6));
|
||||
me6.sin6_family = AF_INET6;
|
||||
me6.sin6_addr = in6addr_any;
|
||||
me6.sin6_port = htons(port);
|
||||
rc = bind(sock, (struct sockaddr *) &me6, sizeof(me6));
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
if(rc < 0) {
|
||||
perror("binding stream socket");
|
||||
logmsg("Error binding socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pidfile = fopen(pidname, "w");
|
||||
if(pidfile) {
|
||||
fprintf(pidfile, "%d\n", (int)getpid());
|
||||
fclose(pidfile);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Couldn't write pid file\n");
|
||||
|
||||
logmsg("Running IPv%d version on port UDP/%d",
|
||||
#ifdef ENABLE_IPV6
|
||||
(use_ipv6?6:4)
|
||||
#else
|
||||
4
|
||||
#endif
|
||||
, port );
|
||||
|
||||
do {
|
||||
FILE *server;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
n = recvfrom(sock, buf, sizeof (buf), 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
if (n < 0) {
|
||||
logmsg("recvfrom:\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
from.sin_family = AF_INET;
|
||||
|
||||
peer = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (peer < 0) {
|
||||
logmsg("socket:\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
|
||||
logmsg("connect: fail\n");
|
||||
return 1;
|
||||
}
|
||||
maxtimeout = 5*TIMEOUT;
|
||||
|
||||
tp = (struct tftphdr *)buf;
|
||||
tp->th_opcode = ntohs(tp->th_opcode);
|
||||
if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) {
|
||||
memset(&test, 0, sizeof(test));
|
||||
server = fopen(REQUEST_DUMP, "ab");
|
||||
if(!server)
|
||||
break;
|
||||
test.server = server;
|
||||
tftp(&test, tp, n);
|
||||
if(test.buffer)
|
||||
free(test.buffer);
|
||||
}
|
||||
fclose(server);
|
||||
sclose(peer);
|
||||
} while(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct formats {
|
||||
const char *f_mode;
|
||||
int f_convert;
|
||||
} formats[] = {
|
||||
{ "netascii", 1 },
|
||||
{ "octet", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Handle initial connection protocol.
|
||||
*/
|
||||
static int tftp(struct testcase *test, struct tftphdr *tp, int size)
|
||||
{
|
||||
char *cp;
|
||||
int first = 1, ecode;
|
||||
struct formats *pf;
|
||||
char *filename, *mode = NULL;
|
||||
|
||||
/* store input protocol */
|
||||
fprintf(test->server, "opcode: %x\n", tp->th_opcode);
|
||||
|
||||
cp = (char *)&tp->th_stuff;
|
||||
filename = cp;
|
||||
again:
|
||||
while (cp < buf + size) {
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
if (*cp) {
|
||||
nak(EBADOP);
|
||||
return 3;
|
||||
}
|
||||
if (first) {
|
||||
mode = ++cp;
|
||||
first = 0;
|
||||
goto again;
|
||||
}
|
||||
/* store input protocol */
|
||||
fprintf(test->server, "filename: %s\n", filename);
|
||||
|
||||
for (cp = mode; *cp; cp++)
|
||||
if (isupper((int)*cp))
|
||||
*cp = tolower((int)*cp);
|
||||
|
||||
/* store input protocol */
|
||||
fprintf(test->server, "mode: %s\n", mode);
|
||||
|
||||
for (pf = formats; pf->f_mode; pf++)
|
||||
if (strcmp(pf->f_mode, mode) == 0)
|
||||
break;
|
||||
if (!pf->f_mode) {
|
||||
nak(EBADOP);
|
||||
return 2;
|
||||
}
|
||||
ecode = validate_access(test, filename, tp->th_opcode);
|
||||
if (ecode) {
|
||||
nak(ecode);
|
||||
return 1;
|
||||
}
|
||||
if (tp->th_opcode == WRQ)
|
||||
recvtftp(test, pf);
|
||||
else
|
||||
sendtftp(test, pf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate file access.
|
||||
*/
|
||||
static int validate_access(struct testcase *test,
|
||||
const char *filename, int mode)
|
||||
{
|
||||
char *ptr;
|
||||
long testno;
|
||||
|
||||
logmsg("trying to get file: %s mode %x", filename, mode);
|
||||
|
||||
if(!strncmp("/verifiedserver", filename, 15)) {
|
||||
char weare[128];
|
||||
size_t count = sprintf(weare, "WE ROOLZ: %d\r\n", (int)getpid());
|
||||
|
||||
logmsg("Are-we-friendly question received");
|
||||
test->buffer = strdup(weare);
|
||||
test->rptr = test->buffer; /* set read pointer */
|
||||
test->bufsize = count; /* set total count */
|
||||
test->rcount = count; /* set data left to read */
|
||||
return 0; /* fine */
|
||||
}
|
||||
|
||||
/* find the last slash */
|
||||
ptr = strrchr(filename, '/');
|
||||
|
||||
if(ptr) {
|
||||
char *file;
|
||||
|
||||
ptr++; /* skip the slash */
|
||||
|
||||
/* skip all non-numericals following the slash */
|
||||
while(*ptr && !isdigit((int)*ptr))
|
||||
ptr++;
|
||||
|
||||
/* get the number */
|
||||
testno = strtol(ptr, &ptr, 10);
|
||||
|
||||
logmsg("requested test number %d", testno);
|
||||
|
||||
test->num = testno;
|
||||
|
||||
file = test2file(testno);
|
||||
|
||||
if(file) {
|
||||
FILE *stream=fopen(file, "rb");
|
||||
if(!stream) {
|
||||
logmsg("Couldn't open test file: %s", file);
|
||||
return EACCESS;
|
||||
}
|
||||
else {
|
||||
size_t count;
|
||||
test->buffer = (char *)spitout(stream, "reply", "data", &count);
|
||||
fclose(stream);
|
||||
if(test->buffer) {
|
||||
test->rptr = test->buffer; /* set read pointer */
|
||||
test->bufsize = count; /* set total count */
|
||||
test->rcount = count; /* set data left to read */
|
||||
}
|
||||
else
|
||||
return EACCESS;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return EACCESS;
|
||||
}
|
||||
else {
|
||||
logmsg("no slash found in path");
|
||||
return EACCESS; /* failure */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timeout;
|
||||
sigjmp_buf timeoutbuf;
|
||||
|
||||
static void timer(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
|
||||
logmsg("alarm!");
|
||||
|
||||
timeout += rexmtval;
|
||||
if (timeout >= maxtimeout)
|
||||
exit(1);
|
||||
siglongjmp(timeoutbuf, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the requested file.
|
||||
*/
|
||||
static void sendtftp(struct testcase *test, struct formats *pf)
|
||||
{
|
||||
struct tftphdr *dp;
|
||||
struct tftphdr *ap; /* ack packet */
|
||||
unsigned short block = 1;
|
||||
int size, n;
|
||||
|
||||
mysignal(SIGALRM, timer);
|
||||
dp = r_init();
|
||||
ap = (struct tftphdr *)ackbuf;
|
||||
do {
|
||||
size = readit(test, &dp, pf->f_convert);
|
||||
if (size < 0) {
|
||||
nak(errno + 100);
|
||||
return;
|
||||
}
|
||||
dp->th_opcode = htons((u_short)DATA);
|
||||
dp->th_block = htons((u_short)block);
|
||||
timeout = 0;
|
||||
(void) sigsetjmp(timeoutbuf, 1);
|
||||
|
||||
send_data:
|
||||
if (send(peer, dp, size + 4, 0) != size + 4) {
|
||||
logmsg("write\n");
|
||||
return;
|
||||
}
|
||||
read_ahead(test, pf->f_convert);
|
||||
for ( ; ; ) {
|
||||
alarm(rexmtval); /* read the ack */
|
||||
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
|
||||
alarm(0);
|
||||
if (n < 0) {
|
||||
logmsg("read: fail\n");
|
||||
return;
|
||||
}
|
||||
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
||||
ap->th_block = ntohs((u_short)ap->th_block);
|
||||
|
||||
if (ap->th_opcode == ERROR) {
|
||||
logmsg("got ERROR");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ap->th_opcode == ACK) {
|
||||
if (ap->th_block == block) {
|
||||
break;
|
||||
}
|
||||
/* Re-synchronize with the other side */
|
||||
(void) synchnet(peer);
|
||||
if (ap->th_block == (block -1)) {
|
||||
goto send_data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
block++;
|
||||
} while (size == SEGSIZE);
|
||||
}
|
||||
|
||||
static void justquit(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Receive a file.
|
||||
*/
|
||||
static void recvtftp(struct testcase *test, struct formats *pf)
|
||||
{
|
||||
struct tftphdr *dp;
|
||||
struct tftphdr *ap; /* ack buffer */
|
||||
unsigned short block = 0;
|
||||
int n, size;
|
||||
|
||||
mysignal(SIGALRM, timer);
|
||||
dp = w_init();
|
||||
ap = (struct tftphdr *)ackbuf;
|
||||
do {
|
||||
timeout = 0;
|
||||
ap->th_opcode = htons((u_short)ACK);
|
||||
ap->th_block = htons((u_short)block);
|
||||
block++;
|
||||
(void) sigsetjmp(timeoutbuf, 1);
|
||||
send_ack:
|
||||
if (send(peer, ackbuf, 4, 0) != 4) {
|
||||
logmsg("write: fail\n");
|
||||
goto abort;
|
||||
}
|
||||
write_behind(test, pf->f_convert);
|
||||
for ( ; ; ) {
|
||||
alarm(rexmtval);
|
||||
n = recv(peer, dp, PKTSIZE, 0);
|
||||
alarm(0);
|
||||
if (n < 0) { /* really? */
|
||||
logmsg("read: fail\n");
|
||||
goto abort;
|
||||
}
|
||||
dp->th_opcode = ntohs((u_short)dp->th_opcode);
|
||||
dp->th_block = ntohs((u_short)dp->th_block);
|
||||
if (dp->th_opcode == ERROR)
|
||||
goto abort;
|
||||
if (dp->th_opcode == DATA) {
|
||||
if (dp->th_block == block) {
|
||||
break; /* normal */
|
||||
}
|
||||
/* Re-synchronize with the other side */
|
||||
(void) synchnet(peer);
|
||||
if (dp->th_block == (block-1))
|
||||
goto send_ack; /* rexmit */
|
||||
}
|
||||
}
|
||||
|
||||
size = writeit(test, &dp, n - 4, pf->f_convert);
|
||||
if (size != (n-4)) { /* ahem */
|
||||
if (size < 0)
|
||||
nak(errno + 100);
|
||||
else
|
||||
nak(ENOSPACE);
|
||||
goto abort;
|
||||
}
|
||||
} while (size == SEGSIZE);
|
||||
write_behind(test, pf->f_convert);
|
||||
|
||||
ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
|
||||
ap->th_block = htons((u_short)(block));
|
||||
(void) send(peer, ackbuf, 4, 0);
|
||||
|
||||
mysignal(SIGALRM, justquit); /* just quit on timeout */
|
||||
alarm(rexmtval);
|
||||
n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
|
||||
alarm(0);
|
||||
if (n >= 4 && /* if read some data */
|
||||
dp->th_opcode == DATA && /* and got a data block */
|
||||
block == dp->th_block) { /* then my last ack was lost */
|
||||
(void) send(peer, ackbuf, 4, 0); /* resend final ack */
|
||||
}
|
||||
abort:
|
||||
return;
|
||||
}
|
||||
|
||||
struct errmsg {
|
||||
int e_code;
|
||||
const char *e_msg;
|
||||
} errmsgs[] = {
|
||||
{ EUNDEF, "Undefined error code" },
|
||||
{ ENOTFOUND, "File not found" },
|
||||
{ EACCESS, "Access violation" },
|
||||
{ ENOSPACE, "Disk full or allocation exceeded" },
|
||||
{ EBADOP, "Illegal TFTP operation" },
|
||||
{ EBADID, "Unknown transfer ID" },
|
||||
{ EEXISTS, "File already exists" },
|
||||
{ ENOUSER, "No such user" },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Send a nak packet (error message). Error code passed in is one of the
|
||||
* standard TFTP codes, or a UNIX errno offset by 100.
|
||||
*/
|
||||
static void nak(int error)
|
||||
{
|
||||
struct tftphdr *tp;
|
||||
int length;
|
||||
struct errmsg *pe;
|
||||
|
||||
tp = (struct tftphdr *)buf;
|
||||
tp->th_opcode = htons((u_short)ERROR);
|
||||
tp->th_code = htons((u_short)error);
|
||||
for (pe = errmsgs; pe->e_code >= 0; pe++)
|
||||
if (pe->e_code == error)
|
||||
break;
|
||||
if (pe->e_code < 0) {
|
||||
pe->e_msg = strerror(error - 100);
|
||||
tp->th_code = EUNDEF; /* set 'undef' errorcode */
|
||||
}
|
||||
strcpy(tp->th_msg, pe->e_msg);
|
||||
length = strlen(pe->e_msg);
|
||||
tp->th_msg[length] = '\0';
|
||||
length += 5;
|
||||
if (send(peer, buf, length, 0) != length)
|
||||
logmsg("nak: fail\n");
|
||||
}
|
@@ -144,3 +144,13 @@ void win32_cleanup(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set by the main code to point to where the test dir is */
|
||||
const char *path=".";
|
||||
|
||||
char *test2file(long testno)
|
||||
{
|
||||
static char filename[256];
|
||||
snprintf(filename, sizeof(filename), TEST_DATA_PATH, path, testno);
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
@@ -33,6 +33,11 @@ void logmsg(const char *msg, ...);
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define TEST_DATA_PATH "%s/data/test%ld"
|
||||
|
||||
/* global variable, where to find the 'data' dir */
|
||||
extern const char *path;
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
@@ -60,3 +65,6 @@ const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
|
||||
|
||||
void win32_init(void);
|
||||
void win32_cleanup(void);
|
||||
|
||||
/* returns the path name to the test case file */
|
||||
char *test2file(long testno);
|
||||
|
@@ -568,8 +568,8 @@ if ($configurebuild && !$crosscompile) {
|
||||
if($runtestopts) {
|
||||
$o = "TEST_F=\"$runtestopts\" ";
|
||||
}
|
||||
logit "$make ${o}test-full";
|
||||
open(F, "$make ${o}test-full 2>&1 |") or die;
|
||||
logit "$make -k ${o}test-full";
|
||||
open(F, "$make -k ${o}test-full 2>&1 |") or die;
|
||||
open(LOG, ">$buildlog") or die;
|
||||
while (<F>) {
|
||||
s/$pwd//g;
|
||||
|
Reference in New Issue
Block a user