Compare commits
308 Commits
cares-1_7_
...
curl-7_20_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2f07dad34 | ||
|
|
06ae8ca5a6 | ||
|
|
d33da42334 | ||
|
|
e118cd4ca0 | ||
|
|
71593dfe57 | ||
|
|
0f4a91afde | ||
|
|
2c2464a682 | ||
|
|
880452d2ed | ||
|
|
e3009f2950 | ||
|
|
cad9c3f55f | ||
|
|
12d01bc5f7 | ||
|
|
bc7615ae2d | ||
|
|
7aef172a34 | ||
|
|
f47b84b57f | ||
|
|
1a5749424b | ||
|
|
a9a5a8e45c | ||
|
|
8044366134 | ||
|
|
15efa262bb | ||
|
|
429e544556 | ||
|
|
680434f313 | ||
|
|
c9f46446d5 | ||
|
|
b77d0db59e | ||
|
|
3205ac35b0 | ||
|
|
381a4d6efe | ||
|
|
f6d288a397 | ||
|
|
013ec6a92f | ||
|
|
e2fc294470 | ||
|
|
d1717e7c90 | ||
|
|
e569ff959f | ||
|
|
839b61c32a | ||
|
|
d28b8d3158 | ||
|
|
2dfbd0d050 | ||
|
|
54879d7763 | ||
|
|
49ba75af26 | ||
|
|
232d17ec64 | ||
|
|
bafba6946c | ||
|
|
da23b16ad8 | ||
|
|
46de140aca | ||
|
|
17a2c32ca9 | ||
|
|
9f6c4daa27 | ||
|
|
ea72194650 | ||
|
|
35e220606d | ||
|
|
55f1e787f3 | ||
|
|
516cf5c8dd | ||
|
|
35fbeda003 | ||
|
|
715e3a806f | ||
|
|
6ebd71d186 | ||
|
|
4ee4e66c4f | ||
|
|
4d19ebe738 | ||
|
|
5312fdcd73 | ||
|
|
fce02e1cab | ||
|
|
15ddc1f134 | ||
|
|
d65cf7889b | ||
|
|
ddab9bd2ec | ||
|
|
eff18763a1 | ||
|
|
3e21f1e971 | ||
|
|
ccffed997e | ||
|
|
6259bcd51f | ||
|
|
a4031dbd85 | ||
|
|
2f3bce1193 | ||
|
|
3cb76e5ebb | ||
|
|
6418c0588d | ||
|
|
124b35aafe | ||
|
|
bbefdf88fd | ||
|
|
06c96d01d2 | ||
|
|
83e91586ef | ||
|
|
c82a1f95eb | ||
|
|
d34982bb65 | ||
|
|
22ed0f5059 | ||
|
|
9bc897f380 | ||
|
|
9b0e57b0f7 | ||
|
|
1d86ebfc88 | ||
|
|
a9b860765d | ||
|
|
483ff1ca75 | ||
|
|
c054b8bfa7 | ||
|
|
340ab2f87f | ||
|
|
f8b16e5ccb | ||
|
|
4bb80cfd75 | ||
|
|
de2cc11a73 | ||
|
|
c656098ee0 | ||
|
|
94f33457d3 | ||
|
|
80675818e0 | ||
|
|
b0e2d47a3e | ||
|
|
0abd928d3d | ||
|
|
597ad5a2ce | ||
|
|
703fa98a48 | ||
|
|
ec4647c0f9 | ||
|
|
33ce0ec1f1 | ||
|
|
1435864030 | ||
|
|
4a8a731476 | ||
|
|
6636fbf238 | ||
|
|
c94d44505f | ||
|
|
0032ce762e | ||
|
|
bdb338b3c7 | ||
|
|
099eed7bf1 | ||
|
|
bc253a4d5f | ||
|
|
a771fb0d41 | ||
|
|
c047fe8e90 | ||
|
|
e45eefcb90 | ||
|
|
844c19cc5b | ||
|
|
4a8570313a | ||
|
|
e59a5cbe4e | ||
|
|
bfc4c33985 | ||
|
|
5af20c70e4 | ||
|
|
bd7430c1ee | ||
|
|
6e5acc2fc1 | ||
|
|
abe3e6b36c | ||
|
|
105e430641 | ||
|
|
4a349f7a54 | ||
|
|
2f9a17fc44 | ||
|
|
bc4582b68a | ||
|
|
e09718d457 | ||
|
|
2c0418f154 | ||
|
|
a74e885bef | ||
|
|
6291a1cf23 | ||
|
|
a872ff742c | ||
|
|
58a1557088 | ||
|
|
422a7869be | ||
|
|
471e8eefb6 | ||
|
|
d2e1ec58f2 | ||
|
|
48032c0880 | ||
|
|
877dad1e24 | ||
|
|
01030e9240 | ||
|
|
a5ca3f1754 | ||
|
|
77a17a21d1 | ||
|
|
6035a4b044 | ||
|
|
469d3ed591 | ||
|
|
3afe2b65b6 | ||
|
|
afdc3d81e9 | ||
|
|
ccfe279117 | ||
|
|
5b5ff41ef1 | ||
|
|
0a713139f6 | ||
|
|
0687bc6bd6 | ||
|
|
424a8882fb | ||
|
|
3fdced357b | ||
|
|
ce2ac665e4 | ||
|
|
0375f70b5c | ||
|
|
7f8980114b | ||
|
|
312494f25f | ||
|
|
8d97b33347 | ||
|
|
b51b703a5b | ||
|
|
071c38988d | ||
|
|
365e75a270 | ||
|
|
b992928f3d | ||
|
|
32413a8e34 | ||
|
|
ada2774ab2 | ||
|
|
a644af129e | ||
|
|
7624527591 | ||
|
|
383bf1e476 | ||
|
|
8c8df3966b | ||
|
|
4344215309 | ||
|
|
0643829444 | ||
|
|
7525670610 | ||
|
|
b32a96eda0 | ||
|
|
82f5ffff8f | ||
|
|
3fd67b5f36 | ||
|
|
1647d64a4b | ||
|
|
d17416190b | ||
|
|
2158e234aa | ||
|
|
cb348a5b1f | ||
|
|
377b2db05b | ||
|
|
78b7d7f7a8 | ||
|
|
5bec1b1cf0 | ||
|
|
cd7b12edff | ||
|
|
1103d0c718 | ||
|
|
aae97c998a | ||
|
|
017c14cc99 | ||
|
|
b90703f594 | ||
|
|
552c3de357 | ||
|
|
aa2f447400 | ||
|
|
184f92d243 | ||
|
|
a1d701d05a | ||
|
|
a114b7b1c0 | ||
|
|
8524c04ca9 | ||
|
|
31630203b1 | ||
|
|
d37a9c4f87 | ||
|
|
88944eb13a | ||
|
|
bd8096b42b | ||
|
|
1e87e4bb4e | ||
|
|
9bd03483ce | ||
|
|
2e83006603 | ||
|
|
fd903eb6be | ||
|
|
2c93ec5303 | ||
|
|
d79b5a0613 | ||
|
|
a62f32d3c2 | ||
|
|
241c0ad5bd | ||
|
|
605bbfc4c0 | ||
|
|
42d365f199 | ||
|
|
31266ca92a | ||
|
|
3f3f6be825 | ||
|
|
01682cca55 | ||
|
|
99a5a5a3e9 | ||
|
|
eb0479575a | ||
|
|
97141d08f7 | ||
|
|
99e9938617 | ||
|
|
6c6dc3f879 | ||
|
|
a1311e5a24 | ||
|
|
5e6ffe353a | ||
|
|
d7cd761047 | ||
|
|
05488d63d0 | ||
|
|
3184a91ec8 | ||
|
|
0dde9056d7 | ||
|
|
a487c80535 | ||
|
|
1e9a946e6d | ||
|
|
7cd5ffc1bf | ||
|
|
fa6631edd5 | ||
|
|
e70c0913b1 | ||
|
|
5b2a31ae41 | ||
|
|
c796f2646e | ||
|
|
d0f6bde732 | ||
|
|
1bd5784a13 | ||
|
|
1f7d9f4f7b | ||
|
|
b6ac8d62a1 | ||
|
|
4ec17a08bc | ||
|
|
aefe0299e0 | ||
|
|
b89789d82f | ||
|
|
a218235964 | ||
|
|
73ad32e125 | ||
|
|
77625f8560 | ||
|
|
1af64730e0 | ||
|
|
eacf62792f | ||
|
|
6ce407305b | ||
|
|
ae3892e8ab | ||
|
|
c74875d94e | ||
|
|
271dc9c582 | ||
|
|
7bede9180d | ||
|
|
f0917cabb5 | ||
|
|
96395a908a | ||
|
|
e9a993b9e9 | ||
|
|
982fe33924 | ||
|
|
fa188eec7b | ||
|
|
bdd3763980 | ||
|
|
1cfa52b67d | ||
|
|
57d3488a0d | ||
|
|
83d34a246e | ||
|
|
76b3c9d70f | ||
|
|
d911e22d8f | ||
|
|
efd1d9dc04 | ||
|
|
88a0060b2e | ||
|
|
4adf7d62d4 | ||
|
|
6add5baa3a | ||
|
|
2a3dafc0cd | ||
|
|
f912f8d5d2 | ||
|
|
af7a5b297f | ||
|
|
344bbcf259 | ||
|
|
240fa29e94 | ||
|
|
010fe5acd5 | ||
|
|
aeec8e0b38 | ||
|
|
2d15ac3d4e | ||
|
|
53deae3781 | ||
|
|
39cc424e81 | ||
|
|
4d0b0cae9e | ||
|
|
8343cb8910 | ||
|
|
a75d9d9169 | ||
|
|
54c60d0067 | ||
|
|
91d05903b4 | ||
|
|
10a11e3abe | ||
|
|
414180b363 | ||
|
|
7603a29fc3 | ||
|
|
002ed5f298 | ||
|
|
044ba6dad2 | ||
|
|
3802d027cd | ||
|
|
3111701c38 | ||
|
|
2c9644b812 | ||
|
|
99daca5a48 | ||
|
|
a6abbb120e | ||
|
|
b0f548fb56 | ||
|
|
364d76aca7 | ||
|
|
6e9a484ea6 | ||
|
|
303f74c740 | ||
|
|
4ea8ad584b | ||
|
|
19b8a80ee9 | ||
|
|
30eb452adf | ||
|
|
92b9b46831 | ||
|
|
83a6b34803 | ||
|
|
43fefab2a1 | ||
|
|
ec3bb8f727 | ||
|
|
463d2d395c | ||
|
|
2fc1752d6e | ||
|
|
296ebf382c | ||
|
|
b91ed67276 | ||
|
|
315253b367 | ||
|
|
3b1de97eaa | ||
|
|
5ce6454d33 | ||
|
|
0653fa107f | ||
|
|
ebe5339003 | ||
|
|
95362af43c | ||
|
|
d14bf09ab8 | ||
|
|
636d2fe00a | ||
|
|
fb2425b147 | ||
|
|
2286f566d0 | ||
|
|
ed2aa87e63 | ||
|
|
f0826974f2 | ||
|
|
d61690ef46 | ||
|
|
a72ce23f16 | ||
|
|
bfae1bd999 | ||
|
|
8a7231d7ae | ||
|
|
4d922545d5 | ||
|
|
1fc32d866a | ||
|
|
230dc699e2 | ||
|
|
3f6854272f | ||
|
|
448f6684bb | ||
|
|
af06a0e497 | ||
|
|
6e38cc9048 | ||
|
|
a240f4d1df | ||
|
|
6f273b1a5f | ||
|
|
f07f17f2a4 | ||
|
|
c713627412 |
291
CHANGES
291
CHANGES
@@ -6,7 +6,291 @@
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
Version 7.20.0 (9 February 2010)
|
||||||
|
|
||||||
|
Daniel Stenberg (9 Feb 2010)
|
||||||
|
- When downloading compressed content over HTTP and the app asked libcurl to
|
||||||
|
automatically uncompress it with the CURLOPT_ENCODING option, libcurl could
|
||||||
|
wrongly provide the callback with more data than the maximum documented
|
||||||
|
amount. An application could thus get tricked into badness if the maximum
|
||||||
|
limit was trusted to be enforced by libcurl itself (as it is documented).
|
||||||
|
|
||||||
|
This is further detailed and explained in the libcurl security advisory
|
||||||
|
20100209 at
|
||||||
|
|
||||||
|
http://curl.haxx.se/docs/adv_20100209.html
|
||||||
|
|
||||||
|
Daniel Fandrich (3 Feb 2010)
|
||||||
|
- Changed the Watcom makefiles to make them easier to keep in sync with
|
||||||
|
Makefile.inc since that can't be included directly.
|
||||||
|
|
||||||
|
Yang Tse (2 Feb 2010)
|
||||||
|
- Symbol CURL_FORMAT_OFF_T now obsoleted, will be removed in a future release,
|
||||||
|
symbol will not be available when building with CURL_NO_OLDIES defined. Use
|
||||||
|
of CURL_FORMAT_CURL_OFF_T is preferred since 7.19.0
|
||||||
|
|
||||||
|
Daniel Stenberg (1 Feb 2010)
|
||||||
|
- Using the multi_socket API, it turns out at times it seemed to "forget"
|
||||||
|
connections (which caused a hang). It turned out to be an existing (7.19.7)
|
||||||
|
bug in libcurl (that's been around for a long time) and it happened like
|
||||||
|
this:
|
||||||
|
|
||||||
|
The app calls curl_multi_add_handle() to add a new easy handle, libcurl will
|
||||||
|
then set it to timeout in 1 millisecond so libcurl will tell the app about
|
||||||
|
it.
|
||||||
|
|
||||||
|
The app's timeout fires off that there's a timeout, the app calls libcurl as
|
||||||
|
we so often document it:
|
||||||
|
|
||||||
|
do {
|
||||||
|
res = curl_multi_socket_action(... TIMEOUT ...);
|
||||||
|
} while(CURLM_CALL_MULTI_PERFORM == res);
|
||||||
|
|
||||||
|
And this is the problem number one:
|
||||||
|
|
||||||
|
When curl_multi_socket_action() is called with no specific handle, but only
|
||||||
|
a timeout-action, it will *only* perform actions within libcurl that are
|
||||||
|
marked to run at this time. In this case, the request would go from INIT to
|
||||||
|
CONNECT and return CURLM_CALL_MULTI_PERFORM. When the app then calls libcurl
|
||||||
|
again, there's no timer set for this handle so it remains in the CONNECT
|
||||||
|
state. The CONNECT state is a transitional state in libcurl so it reports no
|
||||||
|
sockets there, and thus libcurl never tells the app anything more about that
|
||||||
|
easy handle/connection.
|
||||||
|
|
||||||
|
libcurl _does_ set a 1ms timeout for the handle at the end of
|
||||||
|
multi_runsingle() if it returns CURLM_CALL_MULTI_PERFORM, but since the loop
|
||||||
|
is instant the new job is not ready to run at that point (and there's no
|
||||||
|
code that makes libcurl call the app to update the timout for this new
|
||||||
|
timeout). It will simply rely on that some other timeout will trigger later
|
||||||
|
on or that something else will update the timeout callback. This makes the
|
||||||
|
bug fairly hard to repeat.
|
||||||
|
|
||||||
|
The fix made to adress this issue:
|
||||||
|
|
||||||
|
We introduce a loop in lib/multi.c around all calls to multi_runsingle() and
|
||||||
|
simply check for CURLM_CALL_MULTI_PERFORM internally. This has the added
|
||||||
|
benefit that this goes in line with my long-term wishes to get rid of the
|
||||||
|
CURLM_CALL_MULTI_PERFORM all together from the public API.
|
||||||
|
|
||||||
|
The downside of this fix, is that the counter we return in 'running_handles'
|
||||||
|
in several of our public functions then gets a slightly new and possibly
|
||||||
|
confusing behavior during times:
|
||||||
|
|
||||||
|
If an app adds a handle that fails to connect (very quickly) it may just
|
||||||
|
as well never appear as a 'running_handle' with this fix. Previously it
|
||||||
|
would first bump the counter only to get it decreased again at next call.
|
||||||
|
Even I have used that change in handle counter to signal "end of a
|
||||||
|
transfer". The only *good* way to find the end of a individual transfer
|
||||||
|
is calling curl_multi_info_read() to see if it returns one.
|
||||||
|
|
||||||
|
Of course, if the app previously did the looping before it checked the
|
||||||
|
counter, it really shouldn't be any new effect.
|
||||||
|
|
||||||
|
Yang Tse (26 Jan 2010)
|
||||||
|
- Constantine Sapuntzakis' and Joshua Kwan's work done in the last four months
|
||||||
|
relative to the asynchronous DNS lookups, along with with some integration
|
||||||
|
adjustments I have done are finally committed to CVS.
|
||||||
|
|
||||||
|
Currently these enhancements will benefit builds done using c-ares on any
|
||||||
|
platform as well as Windows builds using the default threaded resolver.
|
||||||
|
|
||||||
|
This release does not make generally available POSIX threaded DNS lookups
|
||||||
|
yet. There is no configure option to enable this feature yet. It is possible
|
||||||
|
to experimantally try this feature running configure with compiler flags that
|
||||||
|
make simultaneous definition of preprocessor symbols USE_THREADS_POSIX and
|
||||||
|
HAVE_PTHREAD_H, as well as whatever reentrancy compiler flags and linker ones
|
||||||
|
are required to link and properly use pthread_* functions on each platform.
|
||||||
|
|
||||||
|
Daniel Stenberg (26 Jan 2010)
|
||||||
|
- Mike Crowe made libcurl return CURLE_COULDNT_RESOLVE_PROXY when it is the
|
||||||
|
proxy that cannot be resolved when using c-ares. This matches the behaviour
|
||||||
|
when not using c-ares.
|
||||||
|
|
||||||
|
Bj<EFBFBD>rn Stenberg (23 Jan 2010)
|
||||||
|
- Added a new flag: -J/--remote-header-name. This option tells the
|
||||||
|
-O/--remote-name option to use the server-specified Content-Disposition
|
||||||
|
filename instead of extracting a filename from the URL.
|
||||||
|
|
||||||
|
Daniel Stenberg (21 Jan 2010)
|
||||||
|
- Chris Conroy brought support for RTSP transfers, and with it comes 8(!) new
|
||||||
|
libcurl options for controlling what to get and how to receive posssibly
|
||||||
|
interleaved RTP data.
|
||||||
|
|
||||||
|
Daniel Stenberg (20 Jan 2010)
|
||||||
|
- As was pointed out on the http-state mailing list, the order of cookies in a
|
||||||
|
HTTP Cookie: header _needs_ to be sorted on the path length in the cases
|
||||||
|
where two cookies using the same name are set more than once using
|
||||||
|
(overlapping) paths. Realizing this, identically named cookies must be
|
||||||
|
sorted correctly. But detecting only identically named cookies and take care
|
||||||
|
of them individually is harder than just to blindly and unconditionally sort
|
||||||
|
all cookies based on their path lengths. All major browsers also already do
|
||||||
|
this, so this makes our behavior one step closer to them in the cookie area.
|
||||||
|
|
||||||
|
Test case 8 was the only one that broke due to this change and I updated it
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
Daniel Stenberg (19 Jan 2010)
|
||||||
|
- David McCreedy brought a fix and a new test case (129) to make libcurl work
|
||||||
|
again when downloading files over FTP using ASCII and it turns out that the
|
||||||
|
final size of the file is not the same as the initial size the server
|
||||||
|
reported. This is very common since servers don't take the newline
|
||||||
|
conversions into account.
|
||||||
|
|
||||||
|
Kamil Dudka (14 Jan 2010)
|
||||||
|
- Suppressed side effect of OpenSSL configure checks, which prevented NSS from
|
||||||
|
being properly detected under certain circumstances. It had been caused by
|
||||||
|
strange behavior of pkg-config when handling PKG_CONFIG_LIBDIR. pkg-config
|
||||||
|
distinguishes among empty and non-existent environment variable in that case.
|
||||||
|
|
||||||
|
Daniel Stenberg (12 Jan 2010)
|
||||||
|
- Gil Weber reported a peculiar flaw with the multi interface when doing SFTP
|
||||||
|
transfers: curl_multi_fdset() would return -1 and not set and file
|
||||||
|
descriptors several times during a transfer of a single file. It turned out
|
||||||
|
to be due to two different flaws now fixed. Gil's excellent recipe helped me
|
||||||
|
nail this.
|
||||||
|
|
||||||
|
Daniel Stenberg (11 Jan 2010)
|
||||||
|
- Made sure that the progress callback is repeatedly called at a regular
|
||||||
|
interval even during very slow connects.
|
||||||
|
|
||||||
|
- The tests/runtests.pl script now checks to see if the test case that runs is
|
||||||
|
present in the tests/data/Makefile.am and outputs a notice message on the
|
||||||
|
screen if not. Each test file has to be included in that Makefile.am to get
|
||||||
|
included in release archives and forgetting to add files there is a common
|
||||||
|
mistake. This is an attempt to make it harder to forget.
|
||||||
|
|
||||||
|
Daniel Stenberg (9 Jan 2010)
|
||||||
|
- Johan van Selst found and fixed a OpenSSL session ref count leak:
|
||||||
|
|
||||||
|
ossl_connect_step3() increments an SSL session handle reference counter on
|
||||||
|
each call. When sessions are re-used this reference counter may be
|
||||||
|
incremented many times, but it will be decremented only once when done (by
|
||||||
|
Curl_ossl_session_free()); and the internal OpenSSL data will not be freed
|
||||||
|
if this reference count remains positive. When a session is re-used the
|
||||||
|
reference counter should be corrected by explicitly calling
|
||||||
|
SSL_SESSION_free() after each consecutive SSL_get1_session() to avoid
|
||||||
|
introducing a memory leak.
|
||||||
|
|
||||||
|
(http://curl.haxx.se/bug/view.cgi?id=2926284)
|
||||||
|
|
||||||
|
Daniel Stenberg (7 Jan 2010)
|
||||||
|
- Make sure the progress callback is called repeatedly even during very slow
|
||||||
|
name resolves when c-ares is used for resolving.
|
||||||
|
|
||||||
|
Claes Jakobsson (6 Jan 2010)
|
||||||
|
- Julien Chaffraix fixed so that the fragment part in an URL is not sent
|
||||||
|
to the server anymore.
|
||||||
|
|
||||||
|
Kamil Dudka (3 Jan 2010)
|
||||||
|
- Julien Chaffraix eliminated a duplicated initialization in singlesocket().
|
||||||
|
|
||||||
|
Daniel Stenberg (2 Jan 2010)
|
||||||
|
- Make curl support --ssl and --ssl-reqd instead of the previous FTP-specific
|
||||||
|
versions --ftp-ssl and --ftp-ssl-reqd as these options are now used to
|
||||||
|
control SSL/TLS for IMAP, POP3 and SMTP as well in addition to FTP. The old
|
||||||
|
option names are still working but the new ones are the ones listed and
|
||||||
|
documented.
|
||||||
|
|
||||||
|
Daniel Stenberg (1 Jan 2010)
|
||||||
|
- Ingmar Runge enhanced libcurl's FTP engine to support the PRET command. This
|
||||||
|
command is a special "hack" used by the drftpd server, but even though it is
|
||||||
|
a custom extension I've deemed it fine to add to libcurl since this server
|
||||||
|
seems to survive and people keep using it and want libcurl to support
|
||||||
|
it. The new libcurl option is named CURLOPT_FTP_USE_PRET, and it is also
|
||||||
|
usable from the curl tool with --ftp-pret. Using this option on a server
|
||||||
|
that doesn't support this command will make libcurl fail.
|
||||||
|
|
||||||
|
I added test cases 1107 and 1108 to verify the functionality.
|
||||||
|
|
||||||
|
The PRET command is documented at
|
||||||
|
http://www.drftpd.org/index.php/Distributed_PASV
|
||||||
|
|
||||||
|
Yang Tse (30 Dec 2009)
|
||||||
|
- Steven M. Schweda improved VMS build system, and Craig A. Berry helped
|
||||||
|
with the patch and testing.
|
||||||
|
|
||||||
|
Daniel Stenberg (26 Dec 2009)
|
||||||
|
- Renato Botelho and Peter Pentchev brought a patch that makes the libcurl
|
||||||
|
headers work correctly even on FreeBSD systems before v8.
|
||||||
|
|
||||||
|
(http://curl.haxx.se/bug/view.cgi?id=2916915)
|
||||||
|
|
||||||
|
Daniel Stenberg (17 Dec 2009)
|
||||||
|
- David Byron fixed Curl_ossl_cleanup to actually call ENGINE_cleanup when
|
||||||
|
available.
|
||||||
|
|
||||||
|
- Follow-up fix for the proxy fix I did for Jon Nelson's bug. It turned out I
|
||||||
|
was a bit too quick and broke test case 1101 with that change. The order of
|
||||||
|
some of the setups is sensitive. I now changed it slightly again to make
|
||||||
|
sure we do them in this order:
|
||||||
|
|
||||||
|
1 - parse URL and figure out what protocol is used in the URL
|
||||||
|
2 - prepend protocol:// to URL if missing
|
||||||
|
3 - parse name+password off URL, which needs to know what protocol is used
|
||||||
|
(since only some allows for name+password in the URL)
|
||||||
|
4 - figure out if a proxy should be used set by an option
|
||||||
|
5 - if no proxy option, check proxy environment variables
|
||||||
|
6 - run the protocol-specific setup function, which needs to have the proxy
|
||||||
|
already set
|
||||||
|
|
||||||
|
Daniel Stenberg (15 Dec 2009)
|
||||||
|
- Jon Nelson found a regression that turned out to be a flaw in how libcurl
|
||||||
|
detects and uses proxies based on the environment variables. If the proxy
|
||||||
|
was given as an explicit option it worked, but due to the setup order
|
||||||
|
mistake proxies would not be used fine for a few protocols when picked up
|
||||||
|
from '[protocol]_proxy'. Obviously this broke after 7.19.4. I now also added
|
||||||
|
test case 1106 that verifies this functionality.
|
||||||
|
|
||||||
|
(http://curl.haxx.se/bug/view.cgi?id=2913886)
|
||||||
|
|
||||||
|
Daniel Stenberg (12 Dec 2009)
|
||||||
|
- IMAP, POP3 and SMTP support and their TLS versions (including IMAPS, POP3S
|
||||||
|
and SMTPS) are now supported. The current state may not yet be solid, but
|
||||||
|
the foundation is in place and the test suite has some initial support for
|
||||||
|
these protocols. Work will now persue to make them nice libcurl citizens
|
||||||
|
until release.
|
||||||
|
|
||||||
|
The work with supporting these new protocols was sponsored by
|
||||||
|
networking4all.com - thanks!
|
||||||
|
|
||||||
|
Daniel Stenberg (10 Dec 2009)
|
||||||
|
- Siegfried Gyuricsko found out that the curl manual said --retry would retry
|
||||||
|
on FTP errors in the transient 5xx range. Transient FTP errors are in the
|
||||||
|
4xx range. The code itself only tried on 5xx errors that occured _at login_.
|
||||||
|
Now the retry code retries on all FTP transfer failures that ended with a
|
||||||
|
4xx response.
|
||||||
|
|
||||||
|
(http://curl.haxx.se/bug/view.cgi?id=2911279)
|
||||||
|
|
||||||
|
- Constantine Sapuntzakis figured out a case which would lead to libcurl
|
||||||
|
accessing alredy freed memory and thus crash when using HTTPS (with
|
||||||
|
OpenSSL), multi interface and the CURLOPT_DEBUGFUNCTION and a certain order
|
||||||
|
of cleaning things up. I fixed it.
|
||||||
|
|
||||||
|
(http://curl.haxx.se/bug/view.cgi?id=2905220)
|
||||||
|
|
||||||
|
Daniel Stenberg (7 Dec 2009)
|
||||||
|
- Martin Storsjo made libcurl use the Expect: 100-continue header for posts
|
||||||
|
with unknown size. Previously it was only used for posts with a known size
|
||||||
|
larger than 1024 bytes.
|
||||||
|
|
||||||
|
Daniel Stenberg (1 Dec 2009)
|
||||||
|
- If the Expect: 100-continue header has been set by the application through
|
||||||
|
curl_easy_setopt with CURLOPT_HTTPHEADER, the library should set
|
||||||
|
data->state.expect100header accordingly - the current code (in 7.19.7 at
|
||||||
|
least) doesn't handle this properly. Martin Storsjo provided the fix!
|
||||||
|
|
||||||
|
Yang Tse (28 Nov 2009)
|
||||||
|
- Added Diffie-Hellman parameters to several test harness certificate files in
|
||||||
|
PEM format. Required by several stunnel versions used by our test harness.
|
||||||
|
|
||||||
|
Daniel Stenberg (28 Nov 2009)
|
||||||
|
- Markus Koetter provided a polished and updated version of Chad Monroe's TFTP
|
||||||
|
rework patch that now integrates TFTP properly into libcurl so that it can
|
||||||
|
be used non-blocking with the multi interface and more. BLKSIZE also works.
|
||||||
|
|
||||||
|
The --tftp-blksize option was added to allow setting the TFTP BLKSIZE from
|
||||||
|
the command line.
|
||||||
|
|
||||||
Daniel Stenberg (26 Nov 2009)
|
Daniel Stenberg (26 Nov 2009)
|
||||||
- Extended and fixed the change I did on Dec 11 for the the progress
|
- Extended and fixed the change I did on Dec 11 for the the progress
|
||||||
@@ -70,6 +354,11 @@ Kamil Dudka (15 Nov 2009)
|
|||||||
(and in particular the list of required libraries) even if a path is given
|
(and in particular the list of required libraries) even if a path is given
|
||||||
as argument to --with-ssl
|
as argument to --with-ssl
|
||||||
|
|
||||||
|
Yang Tse (15 Nov 2009)
|
||||||
|
- I removed enable-thread / disable-thread configure option. These were only
|
||||||
|
placebo options. The library is always built as thread safe as possible on
|
||||||
|
every system.
|
||||||
|
|
||||||
Claes Jakobsson (14 Nov 2009)
|
Claes Jakobsson (14 Nov 2009)
|
||||||
- curl-config now accepts '--configure' to see what arguments was
|
- curl-config now accepts '--configure' to see what arguments was
|
||||||
passed to the configure script when building curl.
|
passed to the configure script when building curl.
|
||||||
@@ -90,6 +379,8 @@ Yang Tse (14 Nov 2009)
|
|||||||
- Constantine Sapuntzakis provided the fix that ensures that an SSL connection
|
- Constantine Sapuntzakis provided the fix that ensures that an SSL connection
|
||||||
won't be reused unless protection level for peer and host verification match.
|
won't be reused unless protection level for peer and host verification match.
|
||||||
|
|
||||||
|
I refactored how preprocessor symbol _THREAD_SAFE definition is done.
|
||||||
|
|
||||||
Kamil Dudka (12 Nov 2009)
|
Kamil Dudka (12 Nov 2009)
|
||||||
- Kevin Baughman provided a fix preventing libcurl-NSS from crash on doubly
|
- Kevin Baughman provided a fix preventing libcurl-NSS from crash on doubly
|
||||||
closed NSPR descriptor. The issue was hard to find, reported several times
|
closed NSPR descriptor. The issue was hard to find, reported several times
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
Curl and libcurl 7.19.8
|
Curl and libcurl 7.20.0
|
||||||
|
|
||||||
Public curl releases: 114
|
Public curl releases: 114
|
||||||
Command line options: 132
|
Command line options: 136
|
||||||
curl_easy_setopt() options: 163
|
curl_easy_setopt() options: 174
|
||||||
Public functions in libcurl: 58
|
Public functions in libcurl: 58
|
||||||
Known libcurl bindings: 38
|
Known libcurl bindings: 39
|
||||||
Contributors: 761
|
Contributors: 761
|
||||||
|
|
||||||
This release includes the following changes:
|
This release includes the following changes:
|
||||||
|
|
||||||
o support SSL_FILETYPE_ENGINE for client certificate
|
o support SSL_FILETYPE_ENGINE for client certificate
|
||||||
o curl-config can now show the arguments used when building curl
|
o curl-config can now show the arguments used when building curl
|
||||||
|
o non-blocking TFTP
|
||||||
|
o send Expect: 100-continue for POSTs with unknown sizes
|
||||||
|
o added support for IMAP(S), POP3(S), SMTP(S) and RTSP
|
||||||
|
o added new curl_easy_setopt() options for SMTP and RTSP
|
||||||
|
o added --mail-from and --mail-rcpt for SMTP
|
||||||
|
o VMS build system enhancements
|
||||||
|
o added support for the PRET ftp command
|
||||||
|
o curl supports --ssl and --ssl-reqd
|
||||||
|
o added -J/--remote-header-name for using server-provided filename with -O
|
||||||
|
o enhanced asynchronous DNS lookups
|
||||||
|
o symbol CURL_FORMAT_OFF_T is obsoleted
|
||||||
|
|
||||||
This release includes the following bugfixes:
|
This release includes the following bugfixes:
|
||||||
|
|
||||||
@@ -26,6 +37,23 @@ This release includes the following bugfixes:
|
|||||||
o HTTP proxy tunnel re-used connection even if tunnel got disabled
|
o HTTP proxy tunnel re-used connection even if tunnel got disabled
|
||||||
o SSL lib post-close write
|
o SSL lib post-close write
|
||||||
o curl failed to report write errors for tiny failed downloads
|
o curl failed to report write errors for tiny failed downloads
|
||||||
|
o TFTP BLKSIZE
|
||||||
|
o Expect: 100-continue handling when set by the application
|
||||||
|
o multi interface with OpenSSL read already freed memory when closing down
|
||||||
|
o --retry didn't do right for FTP transient errors
|
||||||
|
o some *_proxy environment variables didn't function
|
||||||
|
o libcurl-OpenSSL engine cleanup
|
||||||
|
o header include fix for FreeBSD versions before v8
|
||||||
|
o fragment part of URLs are no longer sent to the server
|
||||||
|
o progress callback called repeatedly with c-ares for resolving
|
||||||
|
o OpenSSL session id ref count leak
|
||||||
|
o progress callback called repeatedly during slow connects
|
||||||
|
o curl_multi_fdset() would return -1 too often during SCP/SFTP transfers
|
||||||
|
o FTP file size checks with ASCII transfers
|
||||||
|
o HTTP Cookie: headers sort cookies based on specified path lengths
|
||||||
|
o CURLM_CALL_MULTI_PERFORM fix for multi socket timeout calls
|
||||||
|
o libcurl data callback excessive length:
|
||||||
|
http://curl.haxx.se/docs/adv_20100209.html
|
||||||
|
|
||||||
This release includes the following known bugs:
|
This release includes the following known bugs:
|
||||||
|
|
||||||
@@ -36,6 +64,10 @@ advice from friends like these:
|
|||||||
|
|
||||||
Yang Tse, Kamil Dudka, Christian Schmitz, Constantine Sapuntzakis,
|
Yang Tse, Kamil Dudka, Christian Schmitz, Constantine Sapuntzakis,
|
||||||
Marco Maggi, Camille Moncelier, Claes Jakobsson, Kevin Baughman,
|
Marco Maggi, Camille Moncelier, Claes Jakobsson, Kevin Baughman,
|
||||||
Marc Kleine-Budde, Jad Chamcham, Bjorn Augustsson, David Byron
|
Marc Kleine-Budde, Jad Chamcham, Bjorn Augustsson, David Byron,
|
||||||
|
Markus Koetter, Chad Monroe, Martin Storsjo, Siegfried Gyuricsko,
|
||||||
|
Jon Nelson, Julien Chaffraix, Renato Botelho, Peter Pentchev, Ingmar Runge,
|
||||||
|
Johan van Selst, Charles Kerr, Gil Weber, David McCreedy, Chris Conroy,
|
||||||
|
Bjorn Stenberg, Mike Crowe, Joshua Kwan, Daniel Fandrich, Wesley Miaw
|
||||||
|
|
||||||
Thanks! (and sorry if I forgot to mention someone)
|
Thanks! (and sorry if I forgot to mention someone)
|
||||||
|
|||||||
11
TODO-RELEASE
11
TODO-RELEASE
@@ -1,4 +1,4 @@
|
|||||||
To be addressed in 7.19.8 (planned release: January 2010)
|
To be addressed in 7.20.0 (planned release: January 2010)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
244 - patch for [out] parameters
|
244 - patch for [out] parameters
|
||||||
@@ -12,11 +12,4 @@ To be addressed in 7.19.8 (planned release: January 2010)
|
|||||||
|
|
||||||
253 - add option to disable SNI for TLS handshakes
|
253 - add option to disable SNI for TLS handshakes
|
||||||
|
|
||||||
257 - bug #2891595 DNS cache
|
261 -
|
||||||
|
|
||||||
258 - bug #2891591 Curl_dns_entry
|
|
||||||
|
|
||||||
259 - Avoding connection re-use when using CURLOPT_HTTPPROXYTUNNEL
|
|
||||||
|
|
||||||
260 -
|
|
||||||
|
|
||||||
25
acinclude.m4
25
acinclude.m4
@@ -3190,7 +3190,22 @@ AC_DEFUN([CURL_CHECK_WIN32_LARGEFILE], [
|
|||||||
esac
|
esac
|
||||||
])
|
])
|
||||||
|
|
||||||
dnl CURL_CHECK_PKGCONFIG ($module)
|
dnl CURL_EXPORT_PCDIR ($pcdir)
|
||||||
|
dnl ------------------------
|
||||||
|
dnl if $pcdir is not empty, set PKG_CONFIG_LIBDIR to $pcdir and export
|
||||||
|
dnl
|
||||||
|
dnl we need this macro since pkg-config distinguishes among empty and unset
|
||||||
|
dnl variable while checking PKG_CONFIG_LIBDIR
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_DEFUN([CURL_EXPORT_PCDIR], [
|
||||||
|
if test -n "$1"; then
|
||||||
|
PKG_CONFIG_LIBDIR="$1"
|
||||||
|
export PKG_CONFIG_LIBDIR
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl CURL_CHECK_PKGCONFIG ($module, [$pcdir])
|
||||||
dnl ------------------------
|
dnl ------------------------
|
||||||
dnl search for the pkg-config tool (if not cross-compiling). Set the PKGCONFIG
|
dnl search for the pkg-config tool (if not cross-compiling). Set the PKGCONFIG
|
||||||
dnl variable to hold the path to it, or 'no' if not found/present.
|
dnl variable to hold the path to it, or 'no' if not found/present.
|
||||||
@@ -3198,6 +3213,8 @@ dnl
|
|||||||
dnl If pkg-config is present, check that it has info about the $module or
|
dnl If pkg-config is present, check that it has info about the $module or
|
||||||
dnl return "no" anyway!
|
dnl return "no" anyway!
|
||||||
dnl
|
dnl
|
||||||
|
dnl Optionally PKG_CONFIG_LIBDIR may be given as $pcdir.
|
||||||
|
dnl
|
||||||
|
|
||||||
AC_DEFUN([CURL_CHECK_PKGCONFIG], [
|
AC_DEFUN([CURL_CHECK_PKGCONFIG], [
|
||||||
|
|
||||||
@@ -3216,8 +3233,10 @@ AC_DEFUN([CURL_CHECK_PKGCONFIG], [
|
|||||||
if test x$PKGCONFIG != xno; then
|
if test x$PKGCONFIG != xno; then
|
||||||
AC_MSG_CHECKING([for $1 options with pkg-config])
|
AC_MSG_CHECKING([for $1 options with pkg-config])
|
||||||
dnl ask pkg-config about $1
|
dnl ask pkg-config about $1
|
||||||
$PKGCONFIG --exists $1
|
itexists=`CURL_EXPORT_PCDIR([$2]) dnl
|
||||||
if test "$?" -ne "0"; then
|
$PKGCONFIG --exists $1 >/dev/null 2>&1 && echo 1`
|
||||||
|
|
||||||
|
if test -z "$itexists"; then
|
||||||
dnl pkg-config does not have info about the given module! set the
|
dnl pkg-config does not have info about the given module! set the
|
||||||
dnl variable to 'no'
|
dnl variable to 'no'
|
||||||
PKGCONFIG="no"
|
PKGCONFIG="no"
|
||||||
|
|||||||
19
ares/CHANGES
19
ares/CHANGES
@@ -1,5 +1,24 @@
|
|||||||
Changelog for the c-ares project
|
Changelog for the c-ares project
|
||||||
|
|
||||||
|
* January 28, 2010 (Daniel Stenberg)
|
||||||
|
- Tommie Gannert pointed out a silly bug in ares_process_fd() since it didn't
|
||||||
|
check for broken connections like ares_process() did. Based on that, I
|
||||||
|
merged the two functions into a single generic one with two front-ends.
|
||||||
|
|
||||||
|
* December 29, 2009 (Yang Tse)
|
||||||
|
- Laszlo Tamas Szabo adjusted Makefile.msvc compiler options so that where
|
||||||
|
run-time error checks enabling compiler option /GZ was used it is replaced
|
||||||
|
with equivalent /RTCsu for Visual Studio 2003 and newer versions. Option
|
||||||
|
/GX is replaced with equivalent /EHsc for all versions. Also fixed socket
|
||||||
|
data type for internal configure_socket function.
|
||||||
|
|
||||||
|
* December 21, 2009 (Yang Tse)
|
||||||
|
- Ingmar Runge noticed that Windows config-win32.h configuration file
|
||||||
|
did not include a definition for HAVE_CLOSESOCKET which resulted in
|
||||||
|
function close() being inappropriately used to close sockets.
|
||||||
|
|
||||||
|
Version 1.7.0 (Nov 30, 2009)
|
||||||
|
|
||||||
* November 26, 2009 (Yang Tse)
|
* November 26, 2009 (Yang Tse)
|
||||||
- Larry Lansing fixed ares_parse_srv_reply to properly parse replies
|
- Larry Lansing fixed ares_parse_srv_reply to properly parse replies
|
||||||
which might contain non-SRV answers, skipping over potential non-SRV
|
which might contain non-SRV answers, skipping over potential non-SRV
|
||||||
|
|||||||
@@ -222,13 +222,19 @@ PDBTYPE_CONSOLIDATE = /pdbtype:consolidate
|
|||||||
!UNDEF PDBTYPE_CONSOLIDATE
|
!UNDEF PDBTYPE_CONSOLIDATE
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
|
!IF $(CC_VERS_NUM) <= 70
|
||||||
|
RT_ERROR_CHECKING = /GZ
|
||||||
|
!ELSE
|
||||||
|
RT_ERROR_CHECKING = /RTCsu
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
# Assorted commands and flags
|
# Assorted commands and flags
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
|
|
||||||
CC_CMD_REL = cl.exe /nologo $(RTLIB) /DNDEBUG /O2
|
CC_CMD_REL = cl.exe /nologo $(RTLIB) /DNDEBUG /O2
|
||||||
CC_CMD_DBG = cl.exe /nologo $(RTLIBD) /D_DEBUG /Od /Zi /GZ
|
CC_CMD_DBG = cl.exe /nologo $(RTLIBD) /D_DEBUG /Od /Zi $(RT_ERROR_CHECKING)
|
||||||
CC_CFLAGS = $(CFLAGS) /I. /W3 /GX /FD
|
CC_CFLAGS = $(CFLAGS) /I. /W3 /EHsc /FD
|
||||||
|
|
||||||
RC_CMD_REL = rc.exe /l 0x409 /d "NDEBUG"
|
RC_CMD_REL = rc.exe /l 0x409 /d "NDEBUG"
|
||||||
RC_CMD_DBG = rc.exe /l 0x409 /d "_DEBUG"
|
RC_CMD_DBG = rc.exe /l 0x409 /d "_DEBUG"
|
||||||
|
|||||||
@@ -1,36 +1,17 @@
|
|||||||
This is what's new and changed in the c-ares 1.7.0 release:
|
This is what's new and changed in the c-ares 1.7.1 release:
|
||||||
|
|
||||||
Changed:
|
Changed:
|
||||||
|
|
||||||
o in6_addr is not used in ares.h anymore, but a private ares_in6_addr is
|
o
|
||||||
instead declared and used
|
|
||||||
o ares_gethostbyname() now supports 'AF_UNSPEC' as a family for resolving
|
|
||||||
either AF_INET6 or AF_INET
|
|
||||||
o a build-time configured ares_socklen_t is now used instead of socklen_t
|
|
||||||
o new ares_library_init() and ares_library_cleanup() functions
|
|
||||||
o new --enable-curldebug configure option
|
|
||||||
o ARES_ECANCELLED is now sent as reason for ares_cancel()
|
|
||||||
o added ares_parse_srv_reply()
|
|
||||||
o added ares_parse_txt_reply()
|
|
||||||
o added ares_free_data()
|
|
||||||
o new --enable-symbol-hiding configure option
|
|
||||||
o new Makefile.msvc for any MSVC compiler or MS Visual Studio version
|
|
||||||
o addrttl and addr6ttl structs renamed to ares_addrttl and ares_addr6ttl
|
|
||||||
o naming convention for libraries built with MSVC, see README.msvc
|
|
||||||
|
|
||||||
Fixed:
|
Fixed:
|
||||||
|
|
||||||
o ares_parse_*_reply() functions now return ARES_EBADRESP instead of
|
o closing of sockets on Windows systems
|
||||||
ARES_EBADNAME if the name in the response failed to decode
|
o MSVC deprecated compiler options warnings
|
||||||
o only expose/export symbols starting with 'ares_'
|
o ares_process_fd() didn't check broken connections
|
||||||
o fix \Device\TCP handle leaks triggered by buggy iphlpapi.dll
|
|
||||||
o init without internet gone no longer fails
|
|
||||||
o out of bounds memory overwrite triggered with malformed /etc/hosts file
|
|
||||||
o function prototypes in man pages out of sync with ares.h
|
|
||||||
|
|
||||||
Thanks go to these friendly people for their efforts and contributions:
|
Thanks go to these friendly people for their efforts and contributions:
|
||||||
|
|
||||||
Phil Blundell, Japheth Cleaver, Yang Tse, Gregor Jasny, Joshua Kwan,
|
Ingmar Runge, Laszlo Tamas Szabo, Yang Tse, Tommie Gannert
|
||||||
Timo Teras, Jakub Hrozek, John Engelhart, Larry Lansing
|
|
||||||
|
|
||||||
Have fun!
|
Have fun!
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
/* Copyright 1998 by the Massachusetts Institute of Technology.
|
/* Copyright 1998 by the Massachusetts Institute of Technology.
|
||||||
* Copyright (C) 2004-2009 by Daniel Stenberg
|
* Copyright (C) 2004-2010 by Daniel Stenberg
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this
|
* Permission to use, copy, modify, and distribute this
|
||||||
* software and its documentation for any purpose and without
|
* software and its documentation for any purpose and without
|
||||||
@@ -92,7 +92,7 @@ static void skip_server(ares_channel channel, struct query *query,
|
|||||||
int whichserver);
|
int whichserver);
|
||||||
static void next_server(ares_channel channel, struct query *query,
|
static void next_server(ares_channel channel, struct query *query,
|
||||||
struct timeval *now);
|
struct timeval *now);
|
||||||
static int configure_socket(int s, ares_channel channel);
|
static int configure_socket(ares_socket_t s, ares_channel channel);
|
||||||
static int open_tcp_socket(ares_channel channel, struct server_state *server);
|
static int open_tcp_socket(ares_channel channel, struct server_state *server);
|
||||||
static int open_udp_socket(ares_channel channel, struct server_state *server);
|
static int open_udp_socket(ares_channel channel, struct server_state *server);
|
||||||
static int same_questions(const unsigned char *qbuf, int qlen,
|
static int same_questions(const unsigned char *qbuf, int qlen,
|
||||||
@@ -139,18 +139,28 @@ long ares__timeoffset(struct timeval *now,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generic process function
|
||||||
|
*/
|
||||||
|
static void processfds(ares_channel channel,
|
||||||
|
fd_set *read_fds, ares_socket_t read_fd,
|
||||||
|
fd_set *write_fds, ares_socket_t write_fd)
|
||||||
|
{
|
||||||
|
struct timeval now = ares__tvnow();
|
||||||
|
|
||||||
|
write_tcp_data(channel, write_fds, write_fd, &now);
|
||||||
|
read_tcp_data(channel, read_fds, read_fd, &now);
|
||||||
|
read_udp_packets(channel, read_fds, read_fd, &now);
|
||||||
|
process_timeouts(channel, &now);
|
||||||
|
process_broken_connections(channel, &now);
|
||||||
|
}
|
||||||
|
|
||||||
/* Something interesting happened on the wire, or there was a timeout.
|
/* Something interesting happened on the wire, or there was a timeout.
|
||||||
* See what's up and respond accordingly.
|
* See what's up and respond accordingly.
|
||||||
*/
|
*/
|
||||||
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
|
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
|
||||||
{
|
{
|
||||||
struct timeval now = ares__tvnow();
|
processfds(channel, read_fds, ARES_SOCKET_BAD, write_fds, ARES_SOCKET_BAD);
|
||||||
|
|
||||||
write_tcp_data(channel, write_fds, ARES_SOCKET_BAD, &now);
|
|
||||||
read_tcp_data(channel, read_fds, ARES_SOCKET_BAD, &now);
|
|
||||||
read_udp_packets(channel, read_fds, ARES_SOCKET_BAD, &now);
|
|
||||||
process_timeouts(channel, &now);
|
|
||||||
process_broken_connections(channel, &now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Something interesting happened on the wire, or there was a timeout.
|
/* Something interesting happened on the wire, or there was a timeout.
|
||||||
@@ -161,12 +171,7 @@ void ares_process_fd(ares_channel channel,
|
|||||||
file descriptors */
|
file descriptors */
|
||||||
ares_socket_t write_fd)
|
ares_socket_t write_fd)
|
||||||
{
|
{
|
||||||
struct timeval now = ares__tvnow();
|
processfds(channel, NULL, read_fd, NULL, write_fd);
|
||||||
|
|
||||||
write_tcp_data(channel, NULL, write_fd, &now);
|
|
||||||
read_tcp_data(channel, NULL, read_fd, &now);
|
|
||||||
read_udp_packets(channel, NULL, read_fd, &now);
|
|
||||||
process_timeouts(channel, &now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -174,7 +179,8 @@ void ares_process_fd(ares_channel channel,
|
|||||||
* otherwise. This is mostly for HP-UX, which could return EAGAIN or
|
* otherwise. This is mostly for HP-UX, which could return EAGAIN or
|
||||||
* EWOULDBLOCK. See this man page
|
* EWOULDBLOCK. See this man page
|
||||||
*
|
*
|
||||||
* http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html?manpage=/usr/share/man/man2.Z/send.2
|
* http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html?
|
||||||
|
* manpage=/usr/share/man/man2.Z/send.2
|
||||||
*/
|
*/
|
||||||
static int try_again(int errnum)
|
static int try_again(int errnum)
|
||||||
{
|
{
|
||||||
@@ -802,8 +808,9 @@ void ares__send_query(ares_channel channel, struct query *query,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setsocknonblock sets the given socket to either blocking or non-blocking mode
|
* setsocknonblock sets the given socket to either blocking or non-blocking
|
||||||
* based on the 'nonblock' boolean argument. This function is highly portable.
|
* mode based on the 'nonblock' boolean argument. This function is highly
|
||||||
|
* portable.
|
||||||
*/
|
*/
|
||||||
static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
|
static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
|
||||||
int nonblock /* TRUE or FALSE */)
|
int nonblock /* TRUE or FALSE */)
|
||||||
@@ -856,7 +863,7 @@ static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int configure_socket(int s, ares_channel channel)
|
static int configure_socket(ares_socket_t s, ares_channel channel)
|
||||||
{
|
{
|
||||||
setsocknonblock(s, TRUE);
|
setsocknonblock(s, TRUE);
|
||||||
|
|
||||||
@@ -902,10 +909,10 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
|
|||||||
|
|
||||||
#ifdef TCP_NODELAY
|
#ifdef TCP_NODELAY
|
||||||
/*
|
/*
|
||||||
* Disable the Nagle algorithm (only relevant for TCP sockets, and thus not in
|
* Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
|
||||||
* configure_socket). In general, in DNS lookups we're pretty much interested
|
* in configure_socket). In general, in DNS lookups we're pretty much
|
||||||
* in firing off a single request and then waiting for a reply, so batching
|
* interested in firing off a single request and then waiting for a reply,
|
||||||
* isn't very interesting in general.
|
* so batching isn't very interesting in general.
|
||||||
*/
|
*/
|
||||||
opt = 1;
|
opt = 1;
|
||||||
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
#define ARES_VERSION_MAJOR 1
|
#define ARES_VERSION_MAJOR 1
|
||||||
#define ARES_VERSION_MINOR 7
|
#define ARES_VERSION_MINOR 7
|
||||||
#define ARES_VERSION_PATCH 0
|
#define ARES_VERSION_PATCH 1
|
||||||
#define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\
|
#define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\
|
||||||
(ARES_VERSION_MINOR<<8)|\
|
(ARES_VERSION_MINOR<<8)|\
|
||||||
(ARES_VERSION_PATCH))
|
(ARES_VERSION_PATCH))
|
||||||
#define ARES_VERSION_STR "1.7.0-CVS"
|
#define ARES_VERSION_STR "1.7.1-CVS"
|
||||||
|
|
||||||
#if (ARES_VERSION >= 0x010700)
|
#if (ARES_VERSION >= 0x010700)
|
||||||
# define CARES_HAVE_ARES_LIBRARY_INIT 1
|
# define CARES_HAVE_ARES_LIBRARY_INIT 1
|
||||||
|
|||||||
@@ -85,6 +85,9 @@
|
|||||||
/* FUNCTIONS */
|
/* FUNCTIONS */
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Define if you have the closesocket function. */
|
||||||
|
#define HAVE_CLOSESOCKET 1
|
||||||
|
|
||||||
/* Define if you have the gethostname function. */
|
/* Define if you have the gethostname function. */
|
||||||
#define HAVE_GETHOSTNAME 1
|
#define HAVE_GETHOSTNAME 1
|
||||||
|
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ typedef int sig_atomic_t;
|
|||||||
* Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid()
|
* Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(VMS) && \
|
#if defined(__VMS) && \
|
||||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||||
#define getpwuid __32_getpwuid
|
#define getpwuid __32_getpwuid
|
||||||
#endif
|
#endif
|
||||||
@@ -425,7 +425,7 @@ typedef int sig_atomic_t;
|
|||||||
* Macro argv_item_t hides platform details to code using it.
|
* Macro argv_item_t hides platform details to code using it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#define argv_item_t __char_ptr32
|
#define argv_item_t __char_ptr32
|
||||||
#else
|
#else
|
||||||
#define argv_item_t char *
|
#define argv_item_t char *
|
||||||
|
|||||||
228
configure.ac
228
configure.ac
@@ -5,7 +5,7 @@
|
|||||||
# | (__| |_| | _ <| |___
|
# | (__| |_| | _ <| |___
|
||||||
# \___|\___/|_| \_\_____|
|
# \___|\___/|_| \_\_____|
|
||||||
#
|
#
|
||||||
# Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
# Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
#
|
#
|
||||||
# This software is licensed as described in the file COPYING, which
|
# This software is licensed as described in the file COPYING, which
|
||||||
# you should have received as part of this distribution. The terms
|
# you should have received as part of this distribution. The terms
|
||||||
@@ -42,6 +42,7 @@ CURL_CHECK_OPTION_DEBUG
|
|||||||
CURL_CHECK_OPTION_OPTIMIZE
|
CURL_CHECK_OPTION_OPTIMIZE
|
||||||
CURL_CHECK_OPTION_WARNINGS
|
CURL_CHECK_OPTION_WARNINGS
|
||||||
CURL_CHECK_OPTION_CURLDEBUG
|
CURL_CHECK_OPTION_CURLDEBUG
|
||||||
|
CURL_CHECK_OPTION_ARES
|
||||||
|
|
||||||
CURL_CHECK_PATH_SEPARATOR_REQUIRED
|
CURL_CHECK_PATH_SEPARATOR_REQUIRED
|
||||||
|
|
||||||
@@ -135,6 +136,7 @@ curl_verbose_msg="enabled (--disable-verbose)"
|
|||||||
curl_sspi_msg="no (--enable-sspi)"
|
curl_sspi_msg="no (--enable-sspi)"
|
||||||
curl_ldap_msg="no (--enable-ldap / --with-ldap-lib / --with-lber-lib)"
|
curl_ldap_msg="no (--enable-ldap / --with-ldap-lib / --with-lber-lib)"
|
||||||
curl_ldaps_msg="no (--enable-ldaps)"
|
curl_ldaps_msg="no (--enable-ldaps)"
|
||||||
|
curl_rtsp_msg="no (--enable-rtsp)"
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Save anything in $LIBS for later
|
dnl Save anything in $LIBS for later
|
||||||
@@ -318,8 +320,10 @@ AC_HELP_STRING([--disable-http],[Disable HTTP support]),
|
|||||||
no)
|
no)
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
AC_DEFINE(CURL_DISABLE_HTTP, 1, [to disable HTTP])
|
AC_DEFINE(CURL_DISABLE_HTTP, 1, [to disable HTTP])
|
||||||
AC_MSG_WARN([disable HTTP disables FTP over proxy])
|
AC_MSG_WARN([disable HTTP disables FTP over proxy and RTSP])
|
||||||
AC_SUBST(CURL_DISABLE_HTTP, [1])
|
AC_SUBST(CURL_DISABLE_HTTP, [1])
|
||||||
|
AC_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP])
|
||||||
|
AC_SUBST(CURL_DISABLE_RTSP, [1])
|
||||||
;;
|
;;
|
||||||
*) AC_MSG_RESULT(yes)
|
*) AC_MSG_RESULT(yes)
|
||||||
;;
|
;;
|
||||||
@@ -416,6 +420,32 @@ AC_HELP_STRING([--disable-ldaps],[Disable LDAPS support]),
|
|||||||
AC_SUBST(CURL_DISABLE_LDAPS, [1])
|
AC_SUBST(CURL_DISABLE_LDAPS, [1])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether to support rtsp])
|
||||||
|
AC_ARG_ENABLE(rtsp,
|
||||||
|
AC_HELP_STRING([--enable-rtsp],[Enable RTSP support])
|
||||||
|
AC_HELP_STRING([--disable-rtsp],[Disable RTSP support]),
|
||||||
|
[ case "$enableval" in
|
||||||
|
no)
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
AC_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP])
|
||||||
|
AC_SUBST(CURL_DISABLE_RTSP, [1])
|
||||||
|
;;
|
||||||
|
*) if test x$CURL_DISABLE_HTTP = x1 ; then
|
||||||
|
AC_MSG_ERROR(HTTP support needs to be enabled in order to enable RTSP support!)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
curl_rtsp_msg="enabled"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac ],
|
||||||
|
if test "x$CURL_DISABLE_HTTP" != "x1"; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
curl_rtsp_msg="enabled"
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
AC_MSG_CHECKING([whether to support proxies])
|
AC_MSG_CHECKING([whether to support proxies])
|
||||||
AC_ARG_ENABLE(proxy,
|
AC_ARG_ENABLE(proxy,
|
||||||
AC_HELP_STRING([--enable-proxy],[Enable proxy support])
|
AC_HELP_STRING([--enable-proxy],[Enable proxy support])
|
||||||
@@ -478,6 +508,57 @@ AC_HELP_STRING([--disable-tftp],[Disable TFTP support]),
|
|||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether to support pop3])
|
||||||
|
AC_ARG_ENABLE(pop3,
|
||||||
|
AC_HELP_STRING([--enable-pop3],[Enable POP3 support])
|
||||||
|
AC_HELP_STRING([--disable-pop3],[Disable POP3 support]),
|
||||||
|
[ case "$enableval" in
|
||||||
|
no)
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
AC_DEFINE(CURL_DISABLE_POP3, 1, [to disable POP3])
|
||||||
|
AC_SUBST(CURL_DISABLE_POP3, [1])
|
||||||
|
;;
|
||||||
|
*) AC_MSG_RESULT(yes)
|
||||||
|
;;
|
||||||
|
esac ],
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether to support imap])
|
||||||
|
AC_ARG_ENABLE(imap,
|
||||||
|
AC_HELP_STRING([--enable-imap],[Enable IMAP support])
|
||||||
|
AC_HELP_STRING([--disable-imap],[Disable IMAP support]),
|
||||||
|
[ case "$enableval" in
|
||||||
|
no)
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
AC_DEFINE(CURL_DISABLE_IMAP, 1, [to disable IMAP])
|
||||||
|
AC_SUBST(CURL_DISABLE_IMAP, [1])
|
||||||
|
;;
|
||||||
|
*) AC_MSG_RESULT(yes)
|
||||||
|
;;
|
||||||
|
esac ],
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether to support smtp])
|
||||||
|
AC_ARG_ENABLE(smtp,
|
||||||
|
AC_HELP_STRING([--enable-smtp],[Enable SMTP support])
|
||||||
|
AC_HELP_STRING([--disable-smtp],[Disable SMTP support]),
|
||||||
|
[ case "$enableval" in
|
||||||
|
no)
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
AC_DEFINE(CURL_DISABLE_SMTP, 1, [to disable SMTP])
|
||||||
|
AC_SUBST(CURL_DISABLE_SMTP, [1])
|
||||||
|
;;
|
||||||
|
*) AC_MSG_RESULT(yes)
|
||||||
|
;;
|
||||||
|
esac ],
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
dnl **********************************************************************
|
dnl **********************************************************************
|
||||||
dnl Check for built-in manual
|
dnl Check for built-in manual
|
||||||
dnl **********************************************************************
|
dnl **********************************************************************
|
||||||
@@ -1154,7 +1235,6 @@ if test X"$OPT_SSL" != Xno; then
|
|||||||
CLEANLDFLAGS="$LDFLAGS"
|
CLEANLDFLAGS="$LDFLAGS"
|
||||||
CLEANCPPFLAGS="$CPPFLAGS"
|
CLEANCPPFLAGS="$CPPFLAGS"
|
||||||
CLEANLIBS="$LIBS"
|
CLEANLIBS="$LIBS"
|
||||||
SAVE_PKG_CONFIG_LIBDIR="$PKG_CONFIG_LIBDIR"
|
|
||||||
|
|
||||||
case "$OPT_SSL" in
|
case "$OPT_SSL" in
|
||||||
yes)
|
yes)
|
||||||
@@ -1182,10 +1262,9 @@ if test X"$OPT_SSL" != Xno; then
|
|||||||
dnl Try pkg-config even when cross-compiling. Since we
|
dnl Try pkg-config even when cross-compiling. Since we
|
||||||
dnl specify PKG_CONFIG_LIBDIR we're only looking where
|
dnl specify PKG_CONFIG_LIBDIR we're only looking where
|
||||||
dnl the user told us to look
|
dnl the user told us to look
|
||||||
PKG_CONFIG_LIBDIR=$OPT_SSL/lib/pkgconfig
|
OPENSSL_PCDIR="$OPT_SSL/lib/pkgconfig"
|
||||||
export PKG_CONFIG_LIBDIR
|
AC_MSG_NOTICE([PKG_CONFIG_LIBDIR will be set to "$OPENSSL_PCDIR"])
|
||||||
AC_MSG_NOTICE([set PKG_CONFIG_LIBDIR to "$PKG_CONFIG_LIBDIR"])
|
if test -e "$OPENSSL_PCDIR/openssl.pc"; then
|
||||||
if test -e "$PKG_CONFIG_LIBDIR/openssl.pc"; then
|
|
||||||
PKGTEST="yes"
|
PKGTEST="yes"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1202,12 +1281,17 @@ if test X"$OPT_SSL" != Xno; then
|
|||||||
|
|
||||||
if test "$PKGTEST" = "yes"; then
|
if test "$PKGTEST" = "yes"; then
|
||||||
|
|
||||||
CURL_CHECK_PKGCONFIG(openssl)
|
CURL_CHECK_PKGCONFIG(openssl, [$OPENSSL_PCDIR])
|
||||||
|
|
||||||
if test "$PKGCONFIG" != "no" ; then
|
if test "$PKGCONFIG" != "no" ; then
|
||||||
SSL_LIBS=`$PKGCONFIG --libs-only-l openssl 2>/dev/null`
|
SSL_LIBS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl
|
||||||
SSL_LDFLAGS=`$PKGCONFIG --libs-only-L openssl 2>/dev/null`
|
$PKGCONFIG --libs-only-l openssl 2>/dev/null`
|
||||||
SSL_CPPFLAGS=`$PKGCONFIG --cflags-only-I openssl 2>/dev/null`
|
|
||||||
|
SSL_LDFLAGS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl
|
||||||
|
$PKGCONFIG --libs-only-L openssl 2>/dev/null`
|
||||||
|
|
||||||
|
SSL_CPPFLAGS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl
|
||||||
|
$PKGCONFIG --cflags-only-I openssl 2>/dev/null`
|
||||||
|
|
||||||
AC_MSG_NOTICE([pkg-config: SSL_LIBS: "$SSL_LIBS"])
|
AC_MSG_NOTICE([pkg-config: SSL_LIBS: "$SSL_LIBS"])
|
||||||
AC_MSG_NOTICE([pkg-config: SSL_LDFLAGS: "$SSL_LDFLAGS"])
|
AC_MSG_NOTICE([pkg-config: SSL_LDFLAGS: "$SSL_LDFLAGS"])
|
||||||
@@ -1225,10 +1309,6 @@ if test X"$OPT_SSL" != Xno; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl we're done using pkg-config for openssl
|
|
||||||
PKG_CONFIG_LIBDIR="$SAVE_PKG_CONFIG_LIBDIR"
|
|
||||||
export PKG_CONFIG_LIBDIR
|
|
||||||
|
|
||||||
dnl finally, set flags to use SSL
|
dnl finally, set flags to use SSL
|
||||||
CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS"
|
CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS"
|
||||||
LDFLAGS="$LDFLAGS $SSL_LDFLAGS"
|
LDFLAGS="$LDFLAGS $SSL_LDFLAGS"
|
||||||
@@ -1346,6 +1426,7 @@ if test X"$OPT_SSL" != Xno; then
|
|||||||
AC_CHECK_FUNCS( RAND_status \
|
AC_CHECK_FUNCS( RAND_status \
|
||||||
RAND_screen \
|
RAND_screen \
|
||||||
RAND_egd \
|
RAND_egd \
|
||||||
|
ENGINE_cleanup \
|
||||||
CRYPTO_cleanup_all_ex_data \
|
CRYPTO_cleanup_all_ex_data \
|
||||||
SSL_get_shutdown )
|
SSL_get_shutdown )
|
||||||
|
|
||||||
@@ -1957,8 +2038,9 @@ CURL_CHECK_STRUCT_TIMEVAL
|
|||||||
CURL_VERIFY_RUNTIMELIBS
|
CURL_VERIFY_RUNTIMELIBS
|
||||||
|
|
||||||
AC_CHECK_SIZEOF(size_t)
|
AC_CHECK_SIZEOF(size_t)
|
||||||
AC_CHECK_SIZEOF(int)
|
|
||||||
AC_CHECK_SIZEOF(long)
|
AC_CHECK_SIZEOF(long)
|
||||||
|
AC_CHECK_SIZEOF(int)
|
||||||
|
AC_CHECK_SIZEOF(short)
|
||||||
CURL_CONFIGURE_LONG
|
CURL_CONFIGURE_LONG
|
||||||
AC_CHECK_SIZEOF(time_t)
|
AC_CHECK_SIZEOF(time_t)
|
||||||
AC_CHECK_SIZEOF(off_t)
|
AC_CHECK_SIZEOF(off_t)
|
||||||
@@ -2194,81 +2276,8 @@ fi
|
|||||||
dnl set variable for use in automakefile(s)
|
dnl set variable for use in automakefile(s)
|
||||||
AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1)
|
AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1)
|
||||||
|
|
||||||
aresembedded="unknown"
|
CURL_CHECK_LIB_ARES
|
||||||
configure_rundir=`pwd`
|
AM_CONDITIONAL(USE_EMBEDDED_ARES, test x$embedded_ares = xyes)
|
||||||
embedded_ares_builddir="$configure_rundir/ares"
|
|
||||||
AC_MSG_CHECKING([whether to enable c-ares])
|
|
||||||
AC_ARG_ENABLE(ares,
|
|
||||||
AC_HELP_STRING([--enable-ares=PATH],[Enable c-ares for name lookups])
|
|
||||||
AC_HELP_STRING([--disable-ares],[Disable c-ares for name lookups]),
|
|
||||||
[ case "$enableval" in
|
|
||||||
no)
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
;;
|
|
||||||
*) AC_MSG_RESULT(yes)
|
|
||||||
|
|
||||||
if test "x$IPV6_ENABLED" = "x1"; then
|
|
||||||
AC_MSG_NOTICE([c-ares may not work properly with ipv6])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_DEFINE(USE_ARES, 1, [Define if you want to enable c-ares support])
|
|
||||||
dnl substitute HAVE_ARES for curl-config and similar
|
|
||||||
HAVE_ARES="1"
|
|
||||||
AC_SUBST(HAVE_ARES)
|
|
||||||
curl_ares_msg="enabled"
|
|
||||||
|
|
||||||
LIBS="-lcares $LIBS"
|
|
||||||
|
|
||||||
dnl For backwards compatibility default to includes/lib in srcdir/ares
|
|
||||||
dnl If a value is specified it is assumed that the libs are in $val/lib
|
|
||||||
dnl and the includes are in $val/include. This is the default setup for
|
|
||||||
dnl ares so it should not be a problem.
|
|
||||||
if test "x$enableval" = "xyes" ; then
|
|
||||||
if test -d "$srcdir/ares"; then
|
|
||||||
aresembedded="yes"
|
|
||||||
AC_CONFIG_SUBDIRS(ares)
|
|
||||||
dnl Since c-ares has installable configured header files, path
|
|
||||||
dnl inclusion is fully done in makefiles for in-tree builds.
|
|
||||||
LDFLAGS="$LDFLAGS -L$embedded_ares_builddir"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$enableval/include"
|
|
||||||
LDFLAGS="$LDFLAGS -L$enableval/lib"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$aresembedded"; then
|
|
||||||
dnl verify that a sufficient c-ares is here if we have pointed one
|
|
||||||
dnl out and don't use the "embedded" ares dir (in which case we don't
|
|
||||||
dnl check it because it might not have been built yet)
|
|
||||||
AC_MSG_CHECKING([that c-ares is good and recent enough])
|
|
||||||
AC_LINK_IFELSE([
|
|
||||||
AC_LANG_PROGRAM([[
|
|
||||||
#include <ares.h>
|
|
||||||
/* set of dummy functions in case c-ares was built with debug */
|
|
||||||
void curl_dofree() { }
|
|
||||||
void curl_sclose() { }
|
|
||||||
void curl_domalloc() { }
|
|
||||||
void curl_docalloc() { }
|
|
||||||
void curl_socket() { }
|
|
||||||
]],[[
|
|
||||||
ares_channel channel;
|
|
||||||
ares_cancel(channel); /* added in 1.2.0 */
|
|
||||||
ares_process_fd(channel, 0, 0); /* added in 1.4.0 */
|
|
||||||
]])
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
],[
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
AC_MSG_ERROR([c-ares library defective or too old])
|
|
||||||
])
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac ],
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
)
|
|
||||||
|
|
||||||
dnl set variable for use in automakefile(s)
|
|
||||||
AM_CONDITIONAL(USE_EMBEDDED_ARES, test x$aresembedded = xyes)
|
|
||||||
|
|
||||||
dnl ************************************************************
|
dnl ************************************************************
|
||||||
dnl disable verbose text strings
|
dnl disable verbose text strings
|
||||||
@@ -2302,7 +2311,7 @@ AC_HELP_STRING([--disable-sspi],[Disable SSPI]),
|
|||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
AC_DEFINE(USE_WINDOWS_SSPI, 1, [to enable SSPI support])
|
AC_DEFINE(USE_WINDOWS_SSPI, 1, [to enable SSPI support])
|
||||||
AC_SUBST(USE_WINDOWS_SSPI, [1])
|
AC_SUBST(USE_WINDOWS_SSPI, [1])
|
||||||
curl_sspi_msg="yes"
|
curl_sspi_msg="enabled"
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
AC_MSG_WARN([--enable-sspi Ignored. Only supported on native Windows builds.])
|
AC_MSG_WARN([--enable-sspi Ignored. Only supported on native Windows builds.])
|
||||||
@@ -2460,7 +2469,7 @@ fi
|
|||||||
if test "x$HAVE_LIBZ" = "x1"; then
|
if test "x$HAVE_LIBZ" = "x1"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES libz"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES libz"
|
||||||
fi
|
fi
|
||||||
if test "x$HAVE_ARES" = "x1"; then
|
if test "x$USE_ARES" = "x1"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
|
||||||
fi
|
fi
|
||||||
if test "x$IDN_ENABLED" = "x1"; then
|
if test "x$IDN_ENABLED" = "x1"; then
|
||||||
@@ -2506,10 +2515,36 @@ fi
|
|||||||
if test "x$CURL_DISABLE_TFTP" != "x1"; then
|
if test "x$CURL_DISABLE_TFTP" != "x1"; then
|
||||||
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TFTP"
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TFTP"
|
||||||
fi
|
fi
|
||||||
|
if test "x$CURL_DISABLE_POP3" != "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3"
|
||||||
|
if test "x$SSL_ENABLED" = "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3S"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test "x$CURL_DISABLE_IMAP" != "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IMAP"
|
||||||
|
if test "x$SSL_ENABLED" = "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IMAPS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test "x$CURL_DISABLE_SMTP" != "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMTP"
|
||||||
|
if test "x$SSL_ENABLED" = "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SMTPS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
if test "x$USE_LIBSSH2" = "x1"; then
|
if test "x$USE_LIBSSH2" = "x1"; then
|
||||||
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
|
||||||
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
|
||||||
fi
|
fi
|
||||||
|
if test "x$CURL_DISABLE_RTSP" != "x1"; then
|
||||||
|
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl replace spaces with newlines
|
||||||
|
dnl sort the lines
|
||||||
|
dnl replace the newlines back to spaces
|
||||||
|
SUPPORT_PROTOCOLS=`echo $SUPPORT_PROTOCOLS | tr ' ' '\012' | sort | tr '\012' ' '`
|
||||||
|
|
||||||
AC_SUBST(SUPPORT_PROTOCOLS)
|
AC_SUBST(SUPPORT_PROTOCOLS)
|
||||||
|
|
||||||
@@ -2525,8 +2560,11 @@ squeeze CURL_LIBS
|
|||||||
squeeze LIBCURL_LIBS
|
squeeze LIBCURL_LIBS
|
||||||
squeeze TEST_SERVER_LIBS
|
squeeze TEST_SERVER_LIBS
|
||||||
|
|
||||||
|
squeeze SUPPORT_FEATURES
|
||||||
|
squeeze SUPPORT_PROTOCOLS
|
||||||
|
|
||||||
if test "x$want_curldebug_assumed" = "xyes" &&
|
if test "x$want_curldebug_assumed" = "xyes" &&
|
||||||
test "x$want_curldebug" = "xyes" && test "x$HAVE_ARES" = "x1"; then
|
test "x$want_curldebug" = "xyes" && test "x$USE_ARES" = "x1"; then
|
||||||
ac_configure_args="$ac_configure_args --enable-curldebug"
|
ac_configure_args="$ac_configure_args --enable-curldebug"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2584,6 +2622,8 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
|
|||||||
ca cert path: ${capath}
|
ca cert path: ${capath}
|
||||||
LDAP support: ${curl_ldap_msg}
|
LDAP support: ${curl_ldap_msg}
|
||||||
LDAPS support: ${curl_ldaps_msg}
|
LDAPS support: ${curl_ldaps_msg}
|
||||||
|
RTSP support: ${curl_rtsp_msg}
|
||||||
|
Protocols: ${SUPPORT_PROTOCOLS}
|
||||||
])
|
])
|
||||||
|
|
||||||
if test "x$soname_bump" = "xyes"; then
|
if test "x$soname_bump" = "xyes"; then
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ Euphoria
|
|||||||
Written by Ray Smith
|
Written by Ray Smith
|
||||||
http://rays-web.com/eulibcurl.htm
|
http://rays-web.com/eulibcurl.htm
|
||||||
|
|
||||||
|
Falcon
|
||||||
|
|
||||||
|
http://www.falconpl.org/index.ftd?page_id=prjs&prj_id=curl
|
||||||
|
|
||||||
Ferite
|
Ferite
|
||||||
|
|
||||||
Written by Paul Querna
|
Written by Paul Querna
|
||||||
|
|||||||
@@ -874,9 +874,9 @@ REDUCING SIZE
|
|||||||
.comment section).
|
.comment section).
|
||||||
|
|
||||||
Using these techniques it is possible to create a basic HTTP-only shared
|
Using these techniques it is possible to create a basic HTTP-only shared
|
||||||
libcurl library for i386 Linux platforms that is only 94 KiB in size, and
|
libcurl library for i386 Linux platforms that is only 98 KiB in size, and
|
||||||
an FTP-only library that is 87 KiB in size (as of libcurl version 7.19.1,
|
an FTP-only library that is 94 KiB in size (as of libcurl version 7.20.0,
|
||||||
using gcc 4.2.2).
|
using gcc 4.3.3).
|
||||||
|
|
||||||
You may find that statically linking libcurl to your application will
|
You may find that statically linking libcurl to your application will
|
||||||
result in a lower total size than dynamically linking.
|
result in a lower total size than dynamically linking.
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ 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
|
changelog of the current development status, as one or more of these problems
|
||||||
may have been fixed since this was written!
|
may have been fixed since this was written!
|
||||||
|
|
||||||
|
74. The HTTP spec allows headers to be merged and become comma-separated
|
||||||
|
instead of being repeated several times. This also include Authenticate: and
|
||||||
|
Proxy-Authenticate: headers and while this hardly every happens in real life
|
||||||
|
it will confuse libcurl which does not properly support it for all headers -
|
||||||
|
like those Authenticate headers.
|
||||||
|
|
||||||
73. if a connection is made to a FTP server but the server then just never
|
73. if a connection is made to a FTP server but the server then just never
|
||||||
sends the 220 response or otherwise is dead slow, libcurl will not
|
sends the 220 response or otherwise is dead slow, libcurl will not
|
||||||
acknowledge the connection timeout during that phase but only the "real"
|
acknowledge the connection timeout during that phase but only the "real"
|
||||||
@@ -13,12 +19,6 @@ may have been fixed since this was written!
|
|||||||
72. "Pausing pipeline problems."
|
72. "Pausing pipeline problems."
|
||||||
http://curl.haxx.se/mail/lib-2009-07/0214.html
|
http://curl.haxx.se/mail/lib-2009-07/0214.html
|
||||||
|
|
||||||
71. TFTP block size / better integration in transfer
|
|
||||||
http://curl.haxx.se/mail/lib-2009-08/0028.html
|
|
||||||
|
|
||||||
Related problems with TFTP is also that currently (7.19.6) upload file sizes
|
|
||||||
are limited to 32MB (http://curl.haxx.se/bug/view.cgi?id=2848436)
|
|
||||||
|
|
||||||
70. Problem re-using easy handle after call to curl_multi_remove_handle
|
70. Problem re-using easy handle after call to curl_multi_remove_handle
|
||||||
http://curl.haxx.se/mail/lib-2009-07/0249.html
|
http://curl.haxx.se/mail/lib-2009-07/0249.html
|
||||||
|
|
||||||
@@ -40,11 +40,6 @@ may have been fixed since this was written!
|
|||||||
properly wait for the connect to be confirmed. See test case 564 for a first
|
properly wait for the connect to be confirmed. See test case 564 for a first
|
||||||
shot at a test case.
|
shot at a test case.
|
||||||
|
|
||||||
64. The threaded resolver used in libcurl on Windows has some kind of race
|
|
||||||
problem when multiple simultanoes resolves are done, like with the multi
|
|
||||||
interface transferring many files in parallell:
|
|
||||||
http://curl.haxx.se/mail/lib-2009-04/0028.html
|
|
||||||
|
|
||||||
63. When CURLOPT_CONNECT_ONLY is used, the handle cannot reliably be re-used
|
63. When CURLOPT_CONNECT_ONLY is used, the handle cannot reliably be re-used
|
||||||
for any further requests or transfers. The work-around is then to close that
|
for any further requests or transfers. The work-around is then to close that
|
||||||
handle with curl_easy_cleanup() and create a new. Some more details:
|
handle with curl_easy_cleanup() and create a new. Some more details:
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ Judson Bishop
|
|||||||
Juergen Wilke
|
Juergen Wilke
|
||||||
Jukka Pihl
|
Jukka Pihl
|
||||||
Julian Noble
|
Julian Noble
|
||||||
|
Julien Chaffraix
|
||||||
Jun-ichiro itojun Hagino
|
Jun-ichiro itojun Hagino
|
||||||
Jurij Smakov
|
Jurij Smakov
|
||||||
Justin Fletcher
|
Justin Fletcher
|
||||||
|
|||||||
23
docs/TODO
23
docs/TODO
@@ -37,8 +37,7 @@
|
|||||||
5. HTTP
|
5. HTTP
|
||||||
5.1 Better persistency for HTTP 1.0
|
5.1 Better persistency for HTTP 1.0
|
||||||
5.2 support FF3 sqlite cookie files
|
5.2 support FF3 sqlite cookie files
|
||||||
5.3 Sort outgoing cookies
|
5.3 Rearrange request header order
|
||||||
5.4 Rearrange request header order
|
|
||||||
|
|
||||||
6. TELNET
|
6. TELNET
|
||||||
6.1 ditch stdin
|
6.1 ditch stdin
|
||||||
@@ -105,6 +104,7 @@
|
|||||||
15.4 remove several functions
|
15.4 remove several functions
|
||||||
15.5 remove CURLOPT_FAILONERROR
|
15.5 remove CURLOPT_FAILONERROR
|
||||||
15.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE
|
15.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE
|
||||||
|
15.7 remove progress meter from libcurl
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
@@ -237,14 +237,7 @@
|
|||||||
We should consider how (lib)curl can/should support this.
|
We should consider how (lib)curl can/should support this.
|
||||||
http://curl.haxx.se/bug/feature.cgi?id=1871388
|
http://curl.haxx.se/bug/feature.cgi?id=1871388
|
||||||
|
|
||||||
5.3 Sort outgoing cookies
|
5.3 Rearrange request header order
|
||||||
|
|
||||||
All the major browsers sort the cookies sent in the Cookie: header based on
|
|
||||||
the length of the path for which the cookie is set with. This could lead to
|
|
||||||
a small fraction of servers to not play well with curl:
|
|
||||||
http://www.ietf.org/mail-archive/web/http-state/current/msg00150.html
|
|
||||||
|
|
||||||
5.4 Rearrange request header order
|
|
||||||
|
|
||||||
Server implementors often make an effort to detect browser and to reject
|
Server implementors often make an effort to detect browser and to reject
|
||||||
clients it can detect to not match. One of the last details we cannot yet
|
clients it can detect to not match. One of the last details we cannot yet
|
||||||
@@ -585,3 +578,13 @@ to provide the data to send.
|
|||||||
Remove support for a global DNS cache. Anything global is silly, and we
|
Remove support for a global DNS cache. Anything global is silly, and we
|
||||||
already offer the share interface for the same functionality but done
|
already offer the share interface for the same functionality but done
|
||||||
"right".
|
"right".
|
||||||
|
|
||||||
|
15.7 remove progress meter from libcurl
|
||||||
|
|
||||||
|
The internally provided progress meter output doesn't belong in the library.
|
||||||
|
Basically no application wants it (apart from curl) but instead applications
|
||||||
|
can and should do their own progress meters using the progress callback.
|
||||||
|
|
||||||
|
The progress callback should then be bumped as well to get proper 64bit
|
||||||
|
variable types passed to it instead of doubles so that big files work
|
||||||
|
correctly.
|
||||||
|
|||||||
55
docs/curl.1
55
docs/curl.1
@@ -5,7 +5,7 @@
|
|||||||
.\" * | (__| |_| | _ <| |___
|
.\" * | (__| |_| | _ <| |___
|
||||||
.\" * \___|\___/|_| \_\_____|
|
.\" * \___|\___/|_| \_\_____|
|
||||||
.\" *
|
.\" *
|
||||||
.\" * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
.\" * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
.\" *
|
.\" *
|
||||||
.\" * This software is licensed as described in the file COPYING, which
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
.\" * you should have received as part of this distribution. The terms
|
.\" * you should have received as part of this distribution. The terms
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
.\" * $Id$
|
.\" * $Id$
|
||||||
.\" **************************************************************************
|
.\" **************************************************************************
|
||||||
.\"
|
.\"
|
||||||
.TH curl 1 "10 July 2008" "Curl 7.19.0" "Curl Manual"
|
.TH curl 1 "28 November 2009" "Curl 7.20.0" "Curl Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
curl \- transfer a URL
|
curl \- transfer a URL
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -461,19 +461,29 @@ will re-use the same IP address it already uses for the control
|
|||||||
connection. (Added in 7.14.2)
|
connection. (Added in 7.14.2)
|
||||||
|
|
||||||
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
|
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
|
||||||
.IP "--ftp-ssl"
|
.IP "--ftp-pret"
|
||||||
(FTP) Try to use SSL/TLS for the FTP connection. Reverts to a non-secure
|
(FTP) Tell curl to send a PRET command before PASV (and EPSV). Certain
|
||||||
connection if the server doesn't support SSL/TLS. See also
|
FTP servers, mainly drftpd, require this non-standard command for
|
||||||
\fI--ftp-ssl-control\fP and \fI--ftp-ssl-reqd\fP for different levels of
|
directory listings as well as up and downloads in PASV mode.
|
||||||
encryption required. (Added in 7.11.0)
|
(Added in 7.20.x)
|
||||||
|
.IP "--ssl"
|
||||||
|
(FTP, POP3, IMAP, SMTP) Try to use SSL/TLS for the connection. Reverts to a
|
||||||
|
non-secure connection if the server doesn't support SSL/TLS. See also
|
||||||
|
\fI--ftp-ssl-control\fP and \fI--ssl-reqd\fP for different levels of
|
||||||
|
encryption required. (Added in 7.20.0)
|
||||||
|
|
||||||
|
This option was formerly known as \fI--ftp-ssl\fP (Added in 7.11.0) and that
|
||||||
|
can still be used but will be removed in a future version.
|
||||||
.IP "--ftp-ssl-control"
|
.IP "--ftp-ssl-control"
|
||||||
(FTP) Require SSL/TLS for the FTP login, clear for transfer. Allows secure
|
(FTP) Require SSL/TLS for the FTP login, clear for transfer. Allows secure
|
||||||
authentication, but non-encrypted data transfers for efficiency. Fails the
|
authentication, but non-encrypted data transfers for efficiency. Fails the
|
||||||
transfer if the server doesn't support SSL/TLS. (Added in 7.16.0)
|
transfer if the server doesn't support SSL/TLS. (Added in 7.16.0)
|
||||||
.IP "--ftp-ssl-reqd"
|
.IP "--ssl-reqd"
|
||||||
(FTP) Require SSL/TLS for the FTP connection.
|
(FTP, POP3, IMAP, SMTP) Require SSL/TLS for the connection. Terminates the
|
||||||
Terminates the connection if the server doesn't support SSL/TLS.
|
connection if the server doesn't support SSL/TLS. (Added in 7.20.0)
|
||||||
(Added in 7.15.5)
|
|
||||||
|
This option was formerly known as \fI--ftp-ssl-reqd\fP (added in 7.15.5) and
|
||||||
|
that can still be used but will be removed in a future version.
|
||||||
.IP "--ftp-ssl-ccc"
|
.IP "--ftp-ssl-ccc"
|
||||||
(FTP) Use CCC (Clear Command Channel)
|
(FTP) Use CCC (Clear Command Channel)
|
||||||
Shuts down the SSL/TLS layer after authenticating. The rest of the
|
Shuts down the SSL/TLS layer after authenticating. The rest of the
|
||||||
@@ -598,6 +608,9 @@ time only.
|
|||||||
make it discard all "session cookies". This will basically have the same effect
|
make it discard all "session cookies". This will basically have the same effect
|
||||||
as if a new session is started. Typical browsers always discard session
|
as if a new session is started. Typical browsers always discard session
|
||||||
cookies when they're closed down.
|
cookies when they're closed down.
|
||||||
|
.IP "-J/--remote-header-name"
|
||||||
|
(HTTP) This option tells the -O/--remote-name option to use the server-specified
|
||||||
|
Content-Disposition filename instead of extracting a filename from the URL.
|
||||||
.IP "-k/--insecure"
|
.IP "-k/--insecure"
|
||||||
(SSL) This option explicitly allows curl to perform "insecure" SSL connections
|
(SSL) This option explicitly allows curl to perform "insecure" SSL connections
|
||||||
and transfers. All SSL connections are attempted to be made secure by using
|
and transfers. All SSL connections are attempted to be made secure by using
|
||||||
@@ -756,7 +769,15 @@ password to all hosts that the site may redirect to. This may or may not
|
|||||||
introduce a security breach if the site redirects you to a site to which
|
introduce a security breach if the site redirects you to a site to which
|
||||||
you'll send your authentication info (which is plaintext in the case of HTTP
|
you'll send your authentication info (which is plaintext in the case of HTTP
|
||||||
Basic authentication).
|
Basic authentication).
|
||||||
|
.IP "--mail-rcpt <address>"
|
||||||
|
(SMTP) Specify a single address that the given mail should get sent to. This
|
||||||
|
option can be used multiple times to specify many recipients.
|
||||||
|
|
||||||
|
(Added in 7.20.0)
|
||||||
|
.IP "--mail-from <address>"
|
||||||
|
(SMTP) Specify a single address that the given mail should get sent from.
|
||||||
|
|
||||||
|
(Added in 7.20.0)
|
||||||
.IP "--max-filesize <bytes>"
|
.IP "--max-filesize <bytes>"
|
||||||
Specify the maximum size (in bytes) of a file to download. If the file
|
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 curl will
|
requested is larger than this value, the transfer will not start and curl will
|
||||||
@@ -1079,7 +1100,7 @@ timestamp.
|
|||||||
If a transient error is returned when curl tries to perform a transfer, it
|
If a transient error is returned when curl tries to perform a transfer, it
|
||||||
will retry this number of times before giving up. Setting the number to 0
|
will retry this number of times before giving up. Setting the number to 0
|
||||||
makes curl do no retries (which is the default). Transient error means either:
|
makes curl do no retries (which is the default). Transient error means either:
|
||||||
a timeout, an FTP 5xx response code or an HTTP 5xx response code.
|
a timeout, an FTP 4xx response code or an HTTP 5xx response code.
|
||||||
|
|
||||||
When curl is about to retry a transfer, it will first wait one second and then
|
When curl is about to retry a transfer, it will first wait one second and then
|
||||||
for all forthcoming retries it will double the waiting time until it reaches
|
for all forthcoming retries it will double the waiting time until it reaches
|
||||||
@@ -1149,6 +1170,8 @@ mutually exclusive.
|
|||||||
If this option is used several times, the last one will be used. (This option
|
If this option is used several times, the last one will be used. (This option
|
||||||
was previously wrongly documented and used as --socks without the number
|
was previously wrongly documented and used as --socks without the number
|
||||||
appended.)
|
appended.)
|
||||||
|
|
||||||
|
This option (as well as \fI--socks4\fP) does not work with IPV6, FTPS or LDAP.
|
||||||
.IP "--socks5-gssapi-service <servicename>"
|
.IP "--socks5-gssapi-service <servicename>"
|
||||||
The default service name for a socks server is rcmd/server-fqdn. This option
|
The default service name for a socks server is rcmd/server-fqdn. This option
|
||||||
allows you to change it.
|
allows you to change it.
|
||||||
@@ -1181,6 +1204,14 @@ TTYPE=<term> Sets the terminal type.
|
|||||||
XDISPLOC=<X display> Sets the X display location.
|
XDISPLOC=<X display> Sets the X display location.
|
||||||
|
|
||||||
NEW_ENV=<var,val> Sets an environment variable.
|
NEW_ENV=<var,val> Sets an environment variable.
|
||||||
|
.IP "--tftp-blksize <value>"
|
||||||
|
(TFTP) Set TFTP BLKSIZE option (must be >512). This is the block size that
|
||||||
|
curl will try to use when tranferring data to or from a TFTP server. By
|
||||||
|
default 512 bytes will be used.
|
||||||
|
|
||||||
|
If this option is used several times, the last one will be used.
|
||||||
|
|
||||||
|
(Added in 7.20.0)
|
||||||
.IP "-T/--upload-file <file>"
|
.IP "-T/--upload-file <file>"
|
||||||
This transfers the specified local file to the remote URL. If there is no file
|
This transfers the specified local file to the remote URL. If there is no file
|
||||||
part in the specified URL, Curl will append the local file name. NOTE that you
|
part in the specified URL, Curl will append the local file name. NOTE that you
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ int main(int argc, char **argv) {
|
|||||||
{
|
{
|
||||||
FILE *outfp;
|
FILE *outfp;
|
||||||
BIO_get_fp(out,&outfp);
|
BIO_get_fp(out,&outfp);
|
||||||
curl_easy_setopt(p.curl, CURLOPT_FILE,outfp);
|
curl_easy_setopt(p.curl, CURLOPT_WRITEDATA, outfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = curl_easy_setopt(p.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun) ;
|
res = curl_easy_setopt(p.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun) ;
|
||||||
|
|||||||
@@ -105,11 +105,14 @@ int main(int argc, char **argv)
|
|||||||
/* See how the transfers went */
|
/* See how the transfers went */
|
||||||
while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
|
while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
|
||||||
if (msg->msg == CURLMSG_DONE) {
|
if (msg->msg == CURLMSG_DONE) {
|
||||||
|
|
||||||
int idx, found = 0;
|
int idx, found = 0;
|
||||||
|
|
||||||
/* Find out which handle this message is about */
|
/* Find out which handle this message is about */
|
||||||
for (idx=0; (!found && (idx<HANDLECOUNT)); idx++) found = (msg->easy_handle == handles[idx]);
|
for (idx=0; idx<HANDLECOUNT; idx++) {
|
||||||
|
found = (msg->easy_handle == handles[idx]);
|
||||||
|
if(found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case HTTP_HANDLE:
|
case HTTP_HANDLE:
|
||||||
|
|||||||
@@ -209,6 +209,28 @@ the previous request didn't match (see \fICURLOPT_TIMECONDITION\fP). Alas, if
|
|||||||
this returns a 1 you know that the reason you didn't get data in return is
|
this returns a 1 you know that the reason you didn't get data in return is
|
||||||
because it didn't fulfill the condition. The long ths argument points to will
|
because it didn't fulfill the condition. The long ths argument points to will
|
||||||
get a zero stored if the condition instead was met. (Added in 7.19.4)
|
get a zero stored if the condition instead was met. (Added in 7.19.4)
|
||||||
|
.IP CURLINFO_RTSP_SESSION_ID
|
||||||
|
Pass a pointer to a char pointer to receive a pointer to a string holding the
|
||||||
|
most recent RTSP Session ID.
|
||||||
|
|
||||||
|
Applications wishing to resume an RTSP session on another connection should
|
||||||
|
retreive this info before closing the active connection.
|
||||||
|
.IP CURLINFO_RTSP_CLIENT_CSEQ
|
||||||
|
Pass a pointer to a long to receive the next CSeq that will be used by the
|
||||||
|
application.
|
||||||
|
.IP CURLINFO_RTSP_SERVER_CSEQ
|
||||||
|
Pass a pointer to a long to receive the next server CSeq that will be expected
|
||||||
|
by the application.
|
||||||
|
|
||||||
|
\fI(NOTE: listening for server initiated requests is currently
|
||||||
|
unimplemented).\fP
|
||||||
|
|
||||||
|
Applications wishing to resume an RTSP session on another connection should
|
||||||
|
retreive this info before closing the active connection.
|
||||||
|
.IP CURLINFO_RTSP_CSEQ_RECV
|
||||||
|
Pass a pointer to a long to receive the most recently received CSeq from the
|
||||||
|
server. If your application encounters a \fICURLE_RTSP_CSEQ_ERROR\fP then you
|
||||||
|
may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this value.
|
||||||
.SH TIMES
|
.SH TIMES
|
||||||
.nf
|
.nf
|
||||||
An overview of the six time values available from curl_easy_getinfo()
|
An overview of the six time values available from curl_easy_getinfo()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
.\" * | (__| |_| | _ <| |___
|
.\" * | (__| |_| | _ <| |___
|
||||||
.\" * \___|\___/|_| \_\_____|
|
.\" * \___|\___/|_| \_\_____|
|
||||||
.\" *
|
.\" *
|
||||||
.\" * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
.\" * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
.\" *
|
.\" *
|
||||||
.\" * This software is licensed as described in the file COPYING, which
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
.\" * you should have received as part of this distribution. The terms
|
.\" * you should have received as part of this distribution. The terms
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
.\" * $Id$
|
.\" * $Id$
|
||||||
.\" **************************************************************************
|
.\" **************************************************************************
|
||||||
.\"
|
.\"
|
||||||
.TH curl_easy_setopt 3 "11 Dec 2008" "libcurl 7.19.3" "libcurl Manual"
|
.TH curl_easy_setopt 3 "1 Jan 2010" "libcurl 7.20.0" "libcurl Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
curl_easy_setopt \- set options for a curl easy handle
|
curl_easy_setopt \- set options for a curl easy handle
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -49,8 +49,8 @@ thus the string storage associated to the pointer argument may be overwritten
|
|||||||
after curl_easy_setopt() returns. Exceptions to this rule are described in
|
after curl_easy_setopt() returns. Exceptions to this rule are described in
|
||||||
the option details below.
|
the option details below.
|
||||||
|
|
||||||
NOTE: before 7.17.0 strings were not copied. Instead the user was forced keep
|
Before version 7.17.0, strings were not copied. Instead the user was forced
|
||||||
them available until libcurl no longer needed them.
|
keep them available until libcurl no longer needed them.
|
||||||
|
|
||||||
The \fIhandle\fP is the return code from a \fIcurl_easy_init(3)\fP or
|
The \fIhandle\fP is the return code from a \fIcurl_easy_init(3)\fP or
|
||||||
\fIcurl_easy_duphandle(3)\fP call.
|
\fIcurl_easy_duphandle(3)\fP call.
|
||||||
@@ -347,9 +347,9 @@ 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.
|
the SSL negotiation. The SSL_CTX pointer will be a new one every time.
|
||||||
|
|
||||||
To use this properly, a non-trivial amount of knowledge of the openssl
|
To use this properly, a non-trivial amount of knowledge of the openssl
|
||||||
libraries is necessary. For example, using this function allows you to use openssl
|
libraries is necessary. For example, using this function allows you to use
|
||||||
callbacks to add additional validation code for certificates, and even to
|
openssl callbacks to add additional validation code for certificates, and even
|
||||||
change the actual URI of an HTTPS request (example used in the lib509 test
|
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
|
case). See also the example section for a replacement of the key, certificate
|
||||||
and trust file settings.
|
and trust file settings.
|
||||||
.IP CURLOPT_SSL_CTX_DATA
|
.IP CURLOPT_SSL_CTX_DATA
|
||||||
@@ -401,6 +401,30 @@ follows:
|
|||||||
|
|
||||||
You will need to override these definitions if they are different on your
|
You will need to override these definitions if they are different on your
|
||||||
system.
|
system.
|
||||||
|
.IP CURLOPT_INTERLEAVEFUNCTION
|
||||||
|
Function pointer that should match the following prototype: \fIsize_t
|
||||||
|
function( void *ptr, size_t size, size_t nmemb, void *stream)\fP. This
|
||||||
|
function gets called by libcurl as soon as it has received interleaved RTP
|
||||||
|
data. This function gets called for each $ block and therefore contains
|
||||||
|
exactly one upper-layer protocol unit (e.g. one RTP packet). Curl writes the
|
||||||
|
interleaved header as well as the included data for each call. The first byte
|
||||||
|
is always an ASCII dollar sign. The dollar sign is followed by a one byte
|
||||||
|
channel identifier and then a 2 byte integer length in network byte order. See
|
||||||
|
\fIRFC 2326 Section 10.12\fP for more information on how RTP interleaving
|
||||||
|
behaves. If unset or set to NULL, curl will use the default write function.
|
||||||
|
|
||||||
|
Interleaved RTP poses some challeneges for the client application. Since the
|
||||||
|
stream data is sharing the RTSP control connection, it is critical to service
|
||||||
|
the RTP in a timely fashion. If the RTP data is not handled quickly,
|
||||||
|
subsequent response processing may become unreasonably delayed and the
|
||||||
|
connection may close. The application may use \fICURL_RTSPREQ_RECEIVE\fP to
|
||||||
|
service RTP data when no requests are desired. If the application makes a
|
||||||
|
request, (e.g. \fICURL_RTSPREQ_PAUSE\fP) then the response handler will
|
||||||
|
process any pending RTP data before marking the request as finished. (Added
|
||||||
|
in 7.20.0)
|
||||||
|
.IP CURLOPT_INTERLEAVEDATA
|
||||||
|
This is the stream that will be passed to \fICURLOPT_INTERLEAVEFUNCTION\fP when
|
||||||
|
interleaved RTP data is received. (Added in 7.20.0)
|
||||||
.SH ERROR OPTIONS
|
.SH ERROR OPTIONS
|
||||||
.IP CURLOPT_ERRORBUFFER
|
.IP CURLOPT_ERRORBUFFER
|
||||||
Pass a char * to a buffer that the libcurl may store human readable error
|
Pass a char * to a buffer that the libcurl may store human readable error
|
||||||
@@ -449,6 +473,9 @@ on which protocols are supported.
|
|||||||
The string given to CURLOPT_URL must be url-encoded and follow RFC 2396
|
The string given to CURLOPT_URL must be url-encoded and follow RFC 2396
|
||||||
(http://curl.haxx.se/rfc/rfc2396.txt).
|
(http://curl.haxx.se/rfc/rfc2396.txt).
|
||||||
|
|
||||||
|
Starting with version 7.20.0, the fragment part of the URI will not be send as
|
||||||
|
part of the path, which was the case previously.
|
||||||
|
|
||||||
\fICURLOPT_URL\fP is the only option that \fBmust\fP be set before
|
\fICURLOPT_URL\fP is the only option that \fBmust\fP be set before
|
||||||
\fIcurl_easy_perform(3)\fP is called.
|
\fIcurl_easy_perform(3)\fP is called.
|
||||||
|
|
||||||
@@ -537,23 +564,23 @@ name.
|
|||||||
Pass a long. This sets the local port number of the socket used for
|
Pass a long. This sets the local port number of the socket used for
|
||||||
connection. This can be used in combination with \fICURLOPT_INTERFACE\fP and
|
connection. This can be used in combination with \fICURLOPT_INTERFACE\fP and
|
||||||
you are recommended to use \fICURLOPT_LOCALPORTRANGE\fP as well when this is
|
you are recommended to use \fICURLOPT_LOCALPORTRANGE\fP as well when this is
|
||||||
set. Note that the only valid port numbers are 1 - 65535. (Added in 7.15.2)
|
set. Valid port numbers are 1 - 65535. (Added in 7.15.2)
|
||||||
.IP CURLOPT_LOCALPORTRANGE
|
.IP CURLOPT_LOCALPORTRANGE
|
||||||
Pass a long. This is the number of attempts libcurl should make to find a
|
Pass a long. This is the number of attempts libcurl should make to find a
|
||||||
working local port number. It starts with the given \fICURLOPT_LOCALPORT\fP
|
working local port number. It starts with the given \fICURLOPT_LOCALPORT\fP
|
||||||
and adds one to the number for each retry. Setting this to 1 or below will
|
and adds one to the number for each retry. Setting this to 1 or below will
|
||||||
make libcurl do only one try for the exact port number. Note that port numbers
|
make libcurl do only one try for the exact port number. Port numbers by nature
|
||||||
by nature are scarce resources that will be busy at times so setting this
|
are scarce resources that will be busy at times so setting this value to
|
||||||
value to something too low might cause unnecessary connection setup
|
something too low might cause unnecessary connection setup failures. (Added in
|
||||||
failures. (Added in 7.15.2)
|
7.15.2)
|
||||||
.IP CURLOPT_DNS_CACHE_TIMEOUT
|
.IP CURLOPT_DNS_CACHE_TIMEOUT
|
||||||
Pass a long, this sets the timeout in seconds. Name resolves will be kept in
|
Pass a long, this sets the timeout in seconds. Name resolves will be kept in
|
||||||
memory for this number of seconds. Set to zero to completely disable
|
memory for this number of seconds. Set to zero to completely disable
|
||||||
caching, or set to -1 to make the cached entries remain forever. By default,
|
caching, or set to -1 to make the cached entries remain forever. By default,
|
||||||
libcurl caches this info for 60 seconds.
|
libcurl caches this info for 60 seconds.
|
||||||
|
|
||||||
NOTE: the name resolve functions of various libc implementations don't re-read
|
The name resolve functions of various libc implementations don't re-read name
|
||||||
name server information unless explicitly told so (for example, by calling
|
server information unless explicitly told so (for example, by calling
|
||||||
\fIres_init(3)\fP). This may cause libcurl to keep using the older server even
|
\fIres_init(3)\fP). This may cause libcurl to keep using the older server even
|
||||||
if DHCP has updated the server info, and this may look like a DNS cache issue
|
if DHCP has updated the server info, and this may look like a DNS cache issue
|
||||||
to the casual libcurl-app user.
|
to the casual libcurl-app user.
|
||||||
@@ -674,12 +701,12 @@ Pass a char * as parameter, which should be pointing to the zero terminated
|
|||||||
user name to use for the transfer while connecting to Proxy.
|
user name to use for the transfer while connecting to Proxy.
|
||||||
|
|
||||||
The CURLOPT_PROXYUSERNAME option should be used in same way as the
|
The CURLOPT_PROXYUSERNAME option should be used in same way as the
|
||||||
\fICURLOPT_PROXYUSERPWD\fP is used. In comparison to \fICURLOPT_PROXYUSERPWD\fP
|
\fICURLOPT_PROXYUSERPWD\fP is used. In comparison to
|
||||||
the CURLOPT_PROXYUSERNAME allows the username to contain a colon,
|
\fICURLOPT_PROXYUSERPWD\fP the CURLOPT_PROXYUSERNAME allows the username to
|
||||||
like in the following example: "sip:user@example.com".
|
contain a colon, like in the following example: "sip:user@example.com". The
|
||||||
Note the CURLOPT_PROXYUSERNAME option is an alternative way to set the user name
|
CURLOPT_PROXYUSERNAME option is an alternative way to set the user name while
|
||||||
while connecting to Proxy. There is no meaning to use it together
|
connecting to Proxy. There is no meaning to use it together with the
|
||||||
with the \fICURLOPT_PROXYUSERPWD\fP option.
|
\fICURLOPT_PROXYUSERPWD\fP option.
|
||||||
|
|
||||||
In order to specify the password to be used in conjunction with the user name
|
In order to specify the password to be used in conjunction with the user name
|
||||||
use the \fICURLOPT_PROXYPASSWORD\fP option. (Added in 7.19.1)
|
use the \fICURLOPT_PROXYPASSWORD\fP option. (Added in 7.19.1)
|
||||||
@@ -736,8 +763,8 @@ it finds suitable. libcurl will automatically select the one it finds most
|
|||||||
secure.
|
secure.
|
||||||
.IP CURLAUTH_ANYSAFE
|
.IP CURLAUTH_ANYSAFE
|
||||||
This is a convenience macro that sets all bits except Basic and thus makes
|
This is a convenience macro that sets all bits except Basic and thus makes
|
||||||
libcurl pick any it finds suitable. libcurl will automatically select the one it
|
libcurl pick any it finds suitable. libcurl will automatically select the one
|
||||||
finds most secure.
|
it finds most secure.
|
||||||
.RE
|
.RE
|
||||||
.IP CURLOPT_PROXYAUTH
|
.IP CURLOPT_PROXYAUTH
|
||||||
Pass a long as parameter, which is set to a bitmask, to tell libcurl which
|
Pass a long as parameter, which is set to a bitmask, to tell libcurl which
|
||||||
@@ -775,7 +802,7 @@ 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
|
returned. \fICURLOPT_MAXREDIRS\fP can be used to limit the number of redirects
|
||||||
libcurl will follow.
|
libcurl will follow.
|
||||||
|
|
||||||
NOTE: since 7.19.4, libcurl can limit to what protocols it will automatically
|
Since 7.19.4, libcurl can limit what protocols it will automatically
|
||||||
follow. The accepted protocols are set with \fICURLOPT_REDIR_PROTOCOLS\fP and
|
follow. The accepted protocols are set with \fICURLOPT_REDIR_PROTOCOLS\fP and
|
||||||
it excludes the FILE protocol by default.
|
it excludes the FILE protocol by default.
|
||||||
.IP CURLOPT_UNRESTRICTED_AUTH
|
.IP CURLOPT_UNRESTRICTED_AUTH
|
||||||
@@ -851,7 +878,7 @@ re-used handle, you must explicitly set the new request type using
|
|||||||
Pass a void * as parameter, which should be the full data to post in an HTTP
|
Pass a void * as parameter, which should be the full data to post in an HTTP
|
||||||
POST operation. You must make sure that the data is formatted the way you want
|
POST operation. You must make sure that the data is formatted the way you want
|
||||||
the server to receive it. libcurl will not convert or encode it for you. Most
|
the server to receive it. libcurl will not convert or encode it for you. Most
|
||||||
web servers will assume this data to be url-encoded. Take note.
|
web servers will assume this data to be url-encoded.
|
||||||
|
|
||||||
The pointed data are NOT copied by the library: as a consequence, they must
|
The pointed data are NOT copied by the library: as a consequence, they must
|
||||||
be preserved by the calling application until the transfer finishes.
|
be preserved by the calling application until the transfer finishes.
|
||||||
@@ -970,9 +997,9 @@ option and thus you need to concatenate them all in one single string. Set
|
|||||||
multiple cookies in one string like this: "name1=content1; name2=content2;"
|
multiple cookies in one string like this: "name1=content1; name2=content2;"
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
Note that this option sets the cookie header explictly in the outgoing
|
This option sets the cookie header explictly in the outgoing request(s). If
|
||||||
request(s). If multiple requests are done due to authentication, followed
|
multiple requests are done due to authentication, followed redirections or
|
||||||
redirections or similar, they will all get this cookie passed on.
|
similar, they will all get this cookie passed on.
|
||||||
|
|
||||||
Using this option multiple times will only make the latest string override the
|
Using this option multiple times will only make the latest string override the
|
||||||
previous ones.
|
previous ones.
|
||||||
@@ -1045,14 +1072,27 @@ progress, and will simply stop the download when the server ends the
|
|||||||
connection. (added in 7.14.1)
|
connection. (added in 7.14.1)
|
||||||
.IP CURLOPT_HTTP_CONTENT_DECODING
|
.IP CURLOPT_HTTP_CONTENT_DECODING
|
||||||
Pass a long to tell libcurl how to act on content decoding. If set to zero,
|
Pass a long to tell libcurl how to act on content decoding. If set to zero,
|
||||||
content decoding will be disabled. If set to 1 it is enabled. Note however
|
content decoding will be disabled. If set to 1 it is enabled. Libcurl has no
|
||||||
that libcurl has no default content decoding but requires you to use
|
default content decoding but requires you to use \fICURLOPT_ENCODING\fP for
|
||||||
\fICURLOPT_ENCODING\fP for that. (added in 7.16.2)
|
that. (added in 7.16.2)
|
||||||
.IP CURLOPT_HTTP_TRANSFER_DECODING
|
.IP CURLOPT_HTTP_TRANSFER_DECODING
|
||||||
Pass a long to tell libcurl how to act on transfer decoding. If set to zero,
|
Pass a long to tell libcurl how to act on transfer decoding. If set to zero,
|
||||||
transfer decoding will be disabled, if set to 1 it is enabled
|
transfer decoding will be disabled, if set to 1 it is enabled
|
||||||
(default). libcurl does chunked transfer decoding by default unless this
|
(default). libcurl does chunked transfer decoding by default unless this
|
||||||
option is set to zero. (added in 7.16.2)
|
option is set to zero. (added in 7.16.2)
|
||||||
|
.SH SMTP OPTIONS
|
||||||
|
.IP CURLOPT_MAIL_FROM
|
||||||
|
Pass a pointer to a zero terminated string as parameter. It will be used to
|
||||||
|
specify the sender address in a mail when sending an SMTP mail with libcurl.
|
||||||
|
|
||||||
|
(Added in 7.20.0)
|
||||||
|
.IP CURLOPT_MAIL_RCPT
|
||||||
|
Pass a pointer to a linked list of recipients to pass to the server in your
|
||||||
|
SMTP mail request. The linked list should be a fully valid list of \fBstruct
|
||||||
|
curl_slist\fP structs 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.
|
||||||
|
|
||||||
|
(Added in 7.20.0)
|
||||||
.SH TFTP OPTIONS
|
.SH TFTP OPTIONS
|
||||||
.IP CURLOPT_TFTP_BLKSIZE
|
.IP CURLOPT_TFTP_BLKSIZE
|
||||||
Specify block size to use for TFTP data transmission. Valid range as per RFC
|
Specify block size to use for TFTP data transmission. Valid range as per RFC
|
||||||
@@ -1147,6 +1187,11 @@ means that it will first attempt to use EPSV before using PASV, but if you
|
|||||||
pass zero to this option, it will not try using EPSV, only plain PASV.
|
pass zero to this option, it will not try using EPSV, only plain PASV.
|
||||||
|
|
||||||
If the server is an IPv6 host, this option will have no effect as of 7.12.3.
|
If the server is an IPv6 host, this option will have no effect as of 7.12.3.
|
||||||
|
.IP CURLOPT_FTP_USE_PRET
|
||||||
|
Pass a long. If the value is 1, it tells curl to send a PRET command before
|
||||||
|
PASV (and EPSV). Certain FTP servers, mainly drftpd, require this non-standard
|
||||||
|
command for directory listings as well as up and downloads in PASV mode. Has
|
||||||
|
no effect when using the active FTP transfers mode. (Added in 7.20.0)
|
||||||
.IP CURLOPT_FTP_CREATE_MISSING_DIRS
|
.IP CURLOPT_FTP_CREATE_MISSING_DIRS
|
||||||
Pass a long. If the value is 1, curl will attempt to create any remote
|
Pass a long. If the value is 1, curl will attempt to create any remote
|
||||||
directory that it fails to CWD into. CWD is the command that changes working
|
directory that it fails to CWD into. CWD is the command that changes working
|
||||||
@@ -1254,6 +1299,107 @@ file \&"normally" (like in the multicwd case). This is somewhat more standards
|
|||||||
compliant than 'nocwd' but without the full penalty of 'multicwd'.
|
compliant than 'nocwd' but without the full penalty of 'multicwd'.
|
||||||
.RE
|
.RE
|
||||||
(Added in 7.15.1)
|
(Added in 7.15.1)
|
||||||
|
.SH RTSP OPTIONS
|
||||||
|
.IP CURLOPT_RTSP_REQUEST
|
||||||
|
Tell libcurl what kind of RTSP request to make. Pass one of the following RTSP
|
||||||
|
enum values. Unless noted otherwise, commands require the Session ID to be
|
||||||
|
initialized. (Added in 7.20.0)
|
||||||
|
.RS
|
||||||
|
.IP CURL_RTSPREQ_OPTIONS
|
||||||
|
Used to retrieve the available methods of the server. The application is
|
||||||
|
responsbile for parsing and obeying the response. \fB(The session ID is not
|
||||||
|
needed for this method.)\fP (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_DESCRIBE
|
||||||
|
Used to get the low level description of a stream. The application should note
|
||||||
|
what formats it understands in the \fI'Accept:'\fP header. Unless set
|
||||||
|
manually, libcurl will automatically fill in \fI'Accept:
|
||||||
|
application/sdp'\fP. Time-condition headers will be added to Describe requests
|
||||||
|
if the \fICURLOPT_TIMECONDITION\fP option is active. \fB(The session ID is not
|
||||||
|
needed for this method)\fP (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_ANNOUNCE
|
||||||
|
When sent by a client, this method changes the description of the session. For
|
||||||
|
example, if a client is using the server to record a meeting, the client can
|
||||||
|
use Announce to inform the server of all the meta-information about the
|
||||||
|
session. ANNOUNCE acts like an HTTP PUT or POST just like
|
||||||
|
\fICURL_RTSPREQ_SET_PARAMETER\fP (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_SETUP
|
||||||
|
Setup is used to initialize the transport layer for the session. The
|
||||||
|
application must set the desired Transport options for a session by using the
|
||||||
|
\fICURLOPT_RTSP_TRANSPORT\fP option prior to calling setup. If no session ID
|
||||||
|
is currently set with \fICURLOPT_RTSP_SESSION_ID\fP, libcurl will extract and
|
||||||
|
use the session ID in the response to this request. \fB(The session ID is not
|
||||||
|
needed for this method).\fP (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_PLAY
|
||||||
|
Send a Play command to the server. Use the \fICURLOPT_RANGE\fP option to
|
||||||
|
modify the playback time (e.g. 'npt=10-15'). (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_PAUSE
|
||||||
|
Send a Pause command to the server. Use the \fICURLOPT_RANGE\fP option with a
|
||||||
|
single value to indicate when the stream should be halted. (e.g. npt='25')
|
||||||
|
(Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_TEARDOWN
|
||||||
|
This command terminates an RTSP session. Simply closing a connection does not
|
||||||
|
terminate the RTSP session since it is valid to control an RTSP session over
|
||||||
|
different connections. (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_GET_PARAMETER
|
||||||
|
Retrieve a parameter from the server. By default, libcurl will automatically
|
||||||
|
include an \fIAccept: text/parameters\fP header unless a custom one is set.
|
||||||
|
Applications wishing to send a heartbeat message (e.g. in the presence of a
|
||||||
|
server-specified timeout) should send use an empty GET_PARAMETER request.
|
||||||
|
(Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_SET_PARAMETER
|
||||||
|
Set a parameter on the server. By default, libcurl will automatically include
|
||||||
|
a \fIContent-Type: text/parameters\fP header unless a custom one is set. The
|
||||||
|
interaction with SET_PARAMTER is much like an HTTP PUT or POST. An application
|
||||||
|
may either use \fICURLOPT_UPLOAD\fP with \fICURLOPT_READDATA\fP like an HTTP
|
||||||
|
PUT, or it may use \fICURLOPT_POSTFIELDS\fP like an HTTP POST. No chunked
|
||||||
|
transfers are allowed, so the application must set the
|
||||||
|
\fICURLOPT_INFILESIZE\fP in the former and \fICURLOPT_POSTFIELDSIZE\fP in the
|
||||||
|
latter. Also, there is no use of multi-part POSTs within RTSP. (Added in
|
||||||
|
7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_RECORD
|
||||||
|
Used to tell the server to record a session. Use the \fICURLOPT_RANGE\fP
|
||||||
|
option to modify the record time. (Added in 7.20.0)
|
||||||
|
.IP CURL_RTSPREQ_RECEIVE
|
||||||
|
This is a special request because it does not send any data to the server. The
|
||||||
|
application may call this function in order to receive interleaved RTP
|
||||||
|
data. It will return after processing one read buffer of data in order to give
|
||||||
|
the application a chance to run. (Added in 7.20.0)
|
||||||
|
.RE
|
||||||
|
.IP CURLOPT_RTSP_SESSION_ID
|
||||||
|
Pass a char * as a parameter to set the value of the current RTSP Session ID
|
||||||
|
for the handle. Useful for resuming an in-progress session. Once this value is
|
||||||
|
set to any non-NULL value, libcurl will return \fICURLE_RTSP_SESSION_ERROR\fP
|
||||||
|
if ID received from the server does not match. If unset (or set to NULL),
|
||||||
|
libcurl will automatically set the ID the first time the server sets it in a
|
||||||
|
response. (Added in 7.20.0)
|
||||||
|
.IP CURLOPT_RTSP_STREAM_URI
|
||||||
|
Set the stream URI to operate on by passing a char * . For example, a single
|
||||||
|
session may be controlling \fIrtsp://foo/twister/audio\fP and
|
||||||
|
\fIrtsp://foo/twister/video\fP and the application can switch to the
|
||||||
|
appropriate stream using this option. If unset, libcurl will default to
|
||||||
|
operating on generic server options by passing '*' in the place of the RTSP
|
||||||
|
Stream URI. This option is distinct from \fICURLOPT_URL\fP. When working with
|
||||||
|
RTSP, the \fICURLOPT_STREAM_URI\fP indicates what URL to send to the server in
|
||||||
|
the request header while the \fICURLOPT_URL\fP indicates where to make the
|
||||||
|
connection to. (e.g. the \fICURLOPT_URL\fP for the above examples might be
|
||||||
|
set to \fIrtsp://foo/twister\fP (Added in 7.20.0)
|
||||||
|
.IP CURLOPT_RTSP_TRANSPORT
|
||||||
|
Pass a char * to tell libcurl what to pass for the Transport: header for this
|
||||||
|
RTSP session. This is mainly a convenience method to avoid needing to set a
|
||||||
|
custom Transport: header for every SETUP request. The application must set a
|
||||||
|
Transport: header before issuing a SETUP request. (Added in 7.20.0)
|
||||||
|
.IP CURLOPT_RTSP_HEADER
|
||||||
|
This option is simply an alias for \fICURLOPT_HTTP_HEADER\fP. Use this to
|
||||||
|
replace the standard headers that RTSP and HTTP share. It is also valid to use
|
||||||
|
the shortcuts such as \fICURLOPT_USERAGENT\fP. (Added in 7.20.0)
|
||||||
|
.IP CURLOPT_RTSP_CLIENT_CSEQ
|
||||||
|
Manually set the the CSEQ number to issue for the next RTSP request. Useful if
|
||||||
|
the application is resuming a previously broken connection. The CSEQ will
|
||||||
|
increment from this new number henceforth. (Added in 7.20.0)
|
||||||
|
.IP CURLOPT_RTSP_SERVER_CSEQ
|
||||||
|
Manually set the CSEQ number to expect for the next RTSP Server->Client
|
||||||
|
request. At the moment, this feature (listening for Server requests) is
|
||||||
|
unimplemented. (Added in 7.20.0)
|
||||||
.SH PROTOCOL OPTIONS
|
.SH PROTOCOL OPTIONS
|
||||||
.IP CURLOPT_TRANSFERTEXT
|
.IP CURLOPT_TRANSFERTEXT
|
||||||
A parameter set to 1 tells the library to use ASCII mode for FTP transfers,
|
A parameter set to 1 tells the library to use ASCII mode for FTP transfers,
|
||||||
@@ -1280,9 +1426,14 @@ want. It should be in the format "X-Y", where X or Y may be left out. HTTP
|
|||||||
transfers also support several intervals, separated with commas as in
|
transfers also support several intervals, separated with commas as in
|
||||||
\fI"X-Y,N-M"\fP. Using this kind of multiple intervals will cause the HTTP
|
\fI"X-Y,N-M"\fP. Using this kind of multiple intervals will cause the HTTP
|
||||||
server to send the response document in pieces (using standard MIME separation
|
server to send the response document in pieces (using standard MIME separation
|
||||||
techniques). Pass a NULL to this option to disable the use of ranges.
|
techniques). For RTSP, the formatting of a range should follow RFC 2326
|
||||||
|
Section 12.29. For RTSP, byte ranges are \fBnot\fP permitted. Instead, ranges
|
||||||
|
should be given in npt, utc, or smpte formats.
|
||||||
|
|
||||||
Ranges work on HTTP, FTP and FILE (since 7.18.0) transfers only.
|
Pass a NULL to this option to disable the use of ranges.
|
||||||
|
|
||||||
|
Ranges work on HTTP, FTP, FILE (since 7.18.0), and RTSP (since 7.20.0)
|
||||||
|
transfers only.
|
||||||
.IP CURLOPT_RESUME_FROM
|
.IP CURLOPT_RESUME_FROM
|
||||||
Pass a long as parameter. It contains the offset in number of bytes that you
|
Pass a long as parameter. It contains the offset in number of bytes that you
|
||||||
want the transfer to start from. Set this option to 0 to make the transfer
|
want the transfer to start from. Set this option to 0 to make the transfer
|
||||||
@@ -1341,8 +1492,8 @@ as a long. See also \fICURLOPT_INFILESIZE_LARGE\fP.
|
|||||||
For uploading using SCP, this option or \fICURLOPT_INFILESIZE_LARGE\fP is
|
For uploading using SCP, this option or \fICURLOPT_INFILESIZE_LARGE\fP is
|
||||||
mandatory.
|
mandatory.
|
||||||
|
|
||||||
Note that this option does not limit how much data libcurl will actually send,
|
This option does not limit how much data libcurl will actually send, as that
|
||||||
as that is controlled entirely by what the read callback returns.
|
is controlled entirely by what the read callback returns.
|
||||||
.IP CURLOPT_INFILESIZE_LARGE
|
.IP CURLOPT_INFILESIZE_LARGE
|
||||||
When uploading a file to a remote site, this option should be used to tell
|
When uploading a file to a remote site, this option should be used to tell
|
||||||
libcurl what the expected size of the infile is. This value should be passed
|
libcurl what the expected size of the infile is. This value should be passed
|
||||||
@@ -1350,8 +1501,8 @@ as a curl_off_t. (Added in 7.11.0)
|
|||||||
|
|
||||||
For uploading using SCP, this option or \fICURLOPT_INFILESIZE\fP is mandatory.
|
For uploading using SCP, this option or \fICURLOPT_INFILESIZE\fP is mandatory.
|
||||||
|
|
||||||
Note that this option does not limit how much data libcurl will actually send,
|
This option does not limit how much data libcurl will actually send, as that
|
||||||
as that is controlled entirely by what the read callback returns.
|
is controlled entirely by what the read callback returns.
|
||||||
.IP CURLOPT_UPLOAD
|
.IP CURLOPT_UPLOAD
|
||||||
A parameter set to 1 tells the library to prepare for an upload. The
|
A parameter set to 1 tells the library to prepare for an upload. The
|
||||||
\fICURLOPT_READDATA\fP and \fICURLOPT_INFILESIZE\fP or
|
\fICURLOPT_READDATA\fP and \fICURLOPT_INFILESIZE\fP or
|
||||||
@@ -1387,7 +1538,8 @@ given limit. This concerns both FTP and HTTP transfers.
|
|||||||
.IP CURLOPT_TIMECONDITION
|
.IP CURLOPT_TIMECONDITION
|
||||||
Pass a long as parameter. This defines how the \fICURLOPT_TIMEVALUE\fP time
|
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
|
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.
|
or \fICURL_TIMECOND_IFUNMODSINCE\fP. This feature applies to HTTP, FTP, and
|
||||||
|
RTSP.
|
||||||
|
|
||||||
The last modification time of a file is not always known and in such instances
|
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 not
|
this feature will have no effect even if the given time condition would not
|
||||||
@@ -1447,9 +1599,9 @@ If you already have performed transfers with this curl handle, setting a
|
|||||||
smaller MAXCONNECTS than before may cause open connections to get closed
|
smaller MAXCONNECTS than before may cause open connections to get closed
|
||||||
unnecessarily.
|
unnecessarily.
|
||||||
|
|
||||||
Note that if you add this easy handle to a multi handle, this setting is not
|
If you add this easy handle to a multi handle, this setting is not
|
||||||
acknowledged, and you must instead use \fIcurl_multi_setopt(3)\fP and
|
acknowledged, and you must instead use \fIcurl_multi_setopt(3)\fP and the
|
||||||
the \fICURLMOPT_MAXCONNECTS\fP option.
|
\fICURLMOPT_MAXCONNECTS\fP option.
|
||||||
.IP CURLOPT_CLOSEPOLICY
|
.IP CURLOPT_CLOSEPOLICY
|
||||||
(Obsolete) This option does nothing.
|
(Obsolete) This option does nothing.
|
||||||
.IP CURLOPT_FRESH_CONNECT
|
.IP CURLOPT_FRESH_CONNECT
|
||||||
@@ -1549,10 +1701,9 @@ operations.
|
|||||||
If the crypto device cannot be set, \fICURLE_SSL_ENGINE_SETFAILED\fP is
|
If the crypto device cannot be set, \fICURLE_SSL_ENGINE_SETFAILED\fP is
|
||||||
returned.
|
returned.
|
||||||
|
|
||||||
Note that even though this option doesn't need any parameter, in some
|
Even though this option doesn't need any parameter, in some configurations
|
||||||
configurations \fIcurl_easy_setopt\fP might be defined as a macro taking
|
\fIcurl_easy_setopt\fP might be defined as a macro taking exactly three
|
||||||
exactly three arguments. Therefore, it's recommended to pass 1 as parameter to
|
arguments. Therefore, it's recommended to pass 1 as parameter to this option.
|
||||||
this option.
|
|
||||||
.IP CURLOPT_SSLVERSION
|
.IP CURLOPT_SSLVERSION
|
||||||
Pass a long as parameter to control what version of SSL/TLS to attempt to use.
|
Pass a long as parameter to control what version of SSL/TLS to attempt to use.
|
||||||
The available options are:
|
The available options are:
|
||||||
@@ -1598,8 +1749,8 @@ combination with the \fICURLOPT_SSL_VERIFYPEER\fP option. If
|
|||||||
\fICURLOPT_SSL_VERIFYPEER\fP is zero, \fICURLOPT_CAINFO\fP need not
|
\fICURLOPT_SSL_VERIFYPEER\fP is zero, \fICURLOPT_CAINFO\fP need not
|
||||||
even indicate an accessible file.
|
even indicate an accessible file.
|
||||||
|
|
||||||
Note that option is by default set to the system path where libcurl's cacert
|
This option is by default set to the system path where libcurl's cacert bundle
|
||||||
bundle is assumed to be stored, as established at build time.
|
is assumed to be stored, as established at build time.
|
||||||
|
|
||||||
When built against NSS, this is the directory that the NSS certificate
|
When built against NSS, this is the directory that the NSS certificate
|
||||||
database resides in.
|
database resides in.
|
||||||
@@ -1608,8 +1759,8 @@ Pass a char * to a zero terminated string naming a file holding a CA
|
|||||||
certificate in PEM format. If the option is set, an additional check against
|
certificate in PEM format. If the option is set, an additional check against
|
||||||
the peer certificate is performed to verify the issuer is indeed the one
|
the peer certificate is performed to verify the issuer is indeed the one
|
||||||
associated with the certificate provided by the option. This additional check
|
associated with the certificate provided by the option. This additional check
|
||||||
is useful in multi-level PKI where one needs to enforce that the peer certificate is
|
is useful in multi-level PKI where one needs to enforce that the peer
|
||||||
from a specific branch of the tree.
|
certificate is from a specific branch of the tree.
|
||||||
|
|
||||||
This option makes sense only when used in combination with the
|
This option makes sense only when used in combination with the
|
||||||
\fICURLOPT_SSL_VERIFYPEER\fP option. Otherwise, the result of the check is not
|
\fICURLOPT_SSL_VERIFYPEER\fP option. Otherwise, the result of the check is not
|
||||||
@@ -1644,8 +1795,8 @@ This option makes sense only when used in combination with the
|
|||||||
|
|
||||||
A specific error code (CURLE_SSL_CRL_BADFILE) is defined with the option. It
|
A specific error code (CURLE_SSL_CRL_BADFILE) is defined with the option. It
|
||||||
is returned when the SSL exchange fails because the CRL file cannot be loaded.
|
is returned when the SSL exchange fails because the CRL file cannot be loaded.
|
||||||
Note that a failure in certificate verification due to a revocation information
|
A failure in certificate verification due to a revocation information found in
|
||||||
found in the CRL does not trigger this specific error. (Added in 7.19.0)
|
the CRL does not trigger this specific error. (Added in 7.19.0)
|
||||||
.IP CURLOPT_CERTINFO
|
.IP CURLOPT_CERTINFO
|
||||||
Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With
|
Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With
|
||||||
this enabled, libcurl (if built with OpenSSL) will extract lots of information
|
this enabled, libcurl (if built with OpenSSL) will extract lots of information
|
||||||
@@ -1712,7 +1863,7 @@ You'll find more details about the NSS cipher lists on this URL:
|
|||||||
.IP CURLOPT_SSL_SESSIONID_CACHE
|
.IP CURLOPT_SSL_SESSIONID_CACHE
|
||||||
Pass a long set to 0 to disable libcurl's use of SSL session-ID caching. Set
|
Pass a long set to 0 to disable libcurl's use of SSL session-ID caching. Set
|
||||||
this to 1 to enable it. By default all transfers are done using the
|
this to 1 to enable it. By default all transfers are done using the
|
||||||
cache. Note that while nothing ever should get hurt by attempting to reuse SSL
|
cache. While nothing ever should get hurt by attempting to reuse SSL
|
||||||
session-IDs, there seem to be broken SSL implementations in the wild that may
|
session-IDs, there seem to be broken SSL implementations in the wild that may
|
||||||
require you to disable this in order for you to succeed. (Added in 7.16.0)
|
require you to disable this in order for you to succeed. (Added in 7.16.0)
|
||||||
.IP CURLOPT_KRBLEVEL
|
.IP CURLOPT_KRBLEVEL
|
||||||
@@ -1740,9 +1891,9 @@ libcurl defaults to using \fB~/.ssh/id_dsa.pub\fP.
|
|||||||
(Added in 7.16.1)
|
(Added in 7.16.1)
|
||||||
.IP CURLOPT_SSH_PRIVATE_KEYFILE
|
.IP CURLOPT_SSH_PRIVATE_KEYFILE
|
||||||
Pass a char * pointing to a file name for your private key. If not used,
|
Pass a char * pointing to a file name for your private key. If not used,
|
||||||
libcurl defaults to using \fB~/.ssh/id_dsa\fP.
|
libcurl defaults to using \fB~/.ssh/id_dsa\fP. If the file is
|
||||||
If the file is password-protected, set the password with \fICURLOPT_KEYPASSWD\fP.
|
password-protected, set the password with \fICURLOPT_KEYPASSWD\fP. (Added in
|
||||||
(Added in 7.16.1)
|
7.16.1)
|
||||||
.IP CURLOPT_SSH_KNOWNHOSTS
|
.IP CURLOPT_SSH_KNOWNHOSTS
|
||||||
Pass a pointer to a zero terminated string holding the file name of the
|
Pass a pointer to a zero terminated string holding the file name of the
|
||||||
known_host file to use. The known_hosts file should use the OpenSSH file
|
known_host file to use. The known_hosts file should use the OpenSSH file
|
||||||
@@ -1761,9 +1912,9 @@ MUST return one of the following return codes to tell libcurl how to act:
|
|||||||
.IP CURLKHSTAT_FINE_ADD_TO_FILE
|
.IP CURLKHSTAT_FINE_ADD_TO_FILE
|
||||||
The host+key is accepted and libcurl will append it to the known_hosts file
|
The host+key is accepted and libcurl will append it to the known_hosts file
|
||||||
before continuing with the connection. This will also add the host+key combo
|
before continuing with the connection. This will also add the host+key combo
|
||||||
to the known_host pool kept in memory if it wasn't already present there. Note
|
to the known_host pool kept in memory if it wasn't already present there. The
|
||||||
that the adding of data to the file is done by completely replacing the file
|
adding of data to the file is done by completely replacing the file with a new
|
||||||
with a new copy, so the permissions of the file must allow this.
|
copy, so the permissions of the file must allow this.
|
||||||
.IP CURLKHSTAT_FINE
|
.IP CURLKHSTAT_FINE
|
||||||
The host+key is accepted libcurl will continue with the connection. This will
|
The host+key is accepted libcurl will continue with the connection. This will
|
||||||
also add the host+key combo to the known_host pool kept in memory if it wasn't
|
also add the host+key combo to the known_host pool kept in memory if it wasn't
|
||||||
|
|||||||
@@ -21,21 +21,22 @@ but be sure to FD_ZERO them before calling this function as
|
|||||||
otherwise remove any others. The \fIcurl_multi_perform(3)\fP function should be
|
otherwise remove any others. The \fIcurl_multi_perform(3)\fP function should be
|
||||||
called as soon as one of them is ready to be read from or written to.
|
called as soon as one of them is ready to be read from or written to.
|
||||||
|
|
||||||
|
To be sure to have up-to-date results, you should call
|
||||||
|
\fIcurl_multi_perform\fP until it does not return CURLM_CALL_MULTI_PERFORM
|
||||||
|
prior to calling \fIcurl_multi_fdset\fP. This will make sure that libcurl has
|
||||||
|
updated the handles' socket states.
|
||||||
|
|
||||||
If no file descriptors are set by libcurl, \fImax_fd\fP will contain -1 when
|
If no file descriptors are set by libcurl, \fImax_fd\fP will contain -1 when
|
||||||
this function returns. Otherwise it will contain the higher descriptor number
|
this function returns. Otherwise it will contain the higher descriptor number
|
||||||
libcurl set.
|
libcurl set.
|
||||||
|
|
||||||
You should also be aware that when doing select(), you should consider using a
|
When doing select(), you should use \fBcurl_multi_timeout\fP to figure out how
|
||||||
rather small (single-digit number of seconds) timeout and call
|
long to wait for action. Call \fIcurl_multi_perform\fP even if no activity has
|
||||||
\fIcurl_multi_perform\fP regularly - even if no activity has been seen on the
|
been seen on the fd_sets after the timeout expires as otherwise internal
|
||||||
fd_sets - as otherwise libcurl-internal retries and timeouts may not work as
|
retries and timeouts may not work as you'd think and want.
|
||||||
you'd think and want.
|
|
||||||
|
|
||||||
Starting with libcurl 7.16.0, you should use \fBcurl_multi_timeout\fP to
|
|
||||||
figure out how long to wait for action.
|
|
||||||
.SH RETURN VALUE
|
.SH RETURN VALUE
|
||||||
CURLMcode type, general libcurl multi interface error code. See
|
CURLMcode type, general libcurl multi interface error code. See
|
||||||
\fIlibcurl-errors(3)\fP
|
\fIlibcurl-errors(3)\fP
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR curl_multi_cleanup "(3), " curl_multi_init "(3), "
|
.BR curl_multi_cleanup "(3), " curl_multi_init "(3), "
|
||||||
.BR curl_multi_timeout "(3) "
|
.BR curl_multi_timeout "(3), " curl_multi_perform "(3) "
|
||||||
|
|||||||
@@ -22,25 +22,26 @@ changed from the previous call (or is less than the amount of easy handles
|
|||||||
you've added to the multi handle), you know that there is one or more
|
you've added to the multi handle), you know that there is one or more
|
||||||
transfers less "running". You can then call \fIcurl_multi_info_read(3)\fP to
|
transfers less "running". You can then call \fIcurl_multi_info_read(3)\fP to
|
||||||
get information about each individual completed transfer, and that returned
|
get information about each individual completed transfer, and that returned
|
||||||
info includes CURLcode and more.
|
info includes CURLcode and more. If an added handle fails very quickly, it may
|
||||||
|
never be counted as a running_handle.
|
||||||
|
|
||||||
When \fIrunning_handles\fP is set to zero (0) on the return of this function,
|
When \fIrunning_handles\fP is set to zero (0) on the return of this function,
|
||||||
there is no longer any transfers in progress.
|
there is no longer any transfers in progress.
|
||||||
.SH "RETURN VALUE"
|
.SH "RETURN VALUE"
|
||||||
CURLMcode type, general libcurl multi interface error code.
|
CURLMcode type, general libcurl multi interface error code.
|
||||||
|
|
||||||
If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this basically means that you
|
Before version 7.20.0: If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this
|
||||||
should call \fIcurl_multi_perform\fP again, before you select() on more
|
basically means that you should call \fIcurl_multi_perform\fP again, before
|
||||||
actions. You don't have to do it immediately, but the return code means that
|
you select() on more actions. You don't have to do it immediately, but the
|
||||||
libcurl may have more data available to return or that there may be more data
|
return code means that libcurl may have more data available to return or that
|
||||||
to send off before it is "satisfied". Do note that \fIcurl_multi_perform(3)\fP
|
there may be more data to send off before it is "satisfied". Do note that
|
||||||
will return \fICURLM_CALL_MULTI_PERFORM\fP only when it wants to be called
|
\fIcurl_multi_perform(3)\fP will return \fICURLM_CALL_MULTI_PERFORM\fP only
|
||||||
again \fBimmediately\fP. When things are fine and there is nothing immediate
|
when it wants to be called again \fBimmediately\fP. When things are fine and
|
||||||
it wants done, it'll return \fICURLM_OK\fP and you need to wait for \&"action"
|
there is nothing immediate it wants done, it'll return \fICURLM_OK\fP and you
|
||||||
and then call this function again.
|
need to wait for \&"action" and then call this function again.
|
||||||
|
|
||||||
NOTE that this only returns errors etc regarding the whole multi stack. Problems
|
This function only returns errors etc regarding the whole multi stack.
|
||||||
still might have occurred on individual transfers even when this
|
Problems still might have occurred on individual transfers even when this
|
||||||
function returns \fICURLM_OK\fP.
|
function returns \fICURLM_OK\fP.
|
||||||
.SH "TYPICAL USAGE"
|
.SH "TYPICAL USAGE"
|
||||||
Most applications will use \fIcurl_multi_fdset(3)\fP to get the multi_handle's
|
Most applications will use \fIcurl_multi_fdset(3)\fP to get the multi_handle's
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ CURL_CSELECT_ERR. When the events on a socket are unknown, pass 0 instead, and
|
|||||||
libcurl will test the descriptor internally.
|
libcurl will test the descriptor internally.
|
||||||
|
|
||||||
At return, the integer \fBrunning_handles\fP points to will contain the number
|
At return, the integer \fBrunning_handles\fP points to will contain the number
|
||||||
of still running easy handles within the multi handle. When this number
|
of running easy handles within the multi handle. When this number reaches
|
||||||
reaches zero, all transfers are complete/done. Note that when you call
|
zero, all transfers are complete/done. When you call
|
||||||
\fIcurl_multi_socket_action(3)\fP on a specific socket and the counter
|
\fIcurl_multi_socket_action(3)\fP on a specific socket and the counter
|
||||||
decreases by one, it DOES NOT necessarily mean that this exact socket/transfer
|
decreases by one, it DOES NOT necessarily mean that this exact socket/transfer
|
||||||
is the one that completed. Use \fIcurl_multi_info_read(3)\fP to figure out
|
is the one that completed. Use \fIcurl_multi_info_read(3)\fP to figure out
|
||||||
@@ -89,19 +89,16 @@ The \fIuserp\fP argument is a private pointer you have previously set with
|
|||||||
.SH "RETURN VALUE"
|
.SH "RETURN VALUE"
|
||||||
CURLMcode type, general libcurl multi interface error code.
|
CURLMcode type, general libcurl multi interface error code.
|
||||||
|
|
||||||
Legacy: If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this basically means
|
Before version 7.20.0: If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this
|
||||||
that you should call \fIcurl_multi_socket_action(3)\fP again, before you wait
|
basically means that you should call \fIcurl_multi_socket_action(3)\fP again
|
||||||
for more actions on libcurl's sockets. You don't have to do it immediately,
|
before you wait for more actions on libcurl's sockets. You don't have to do it
|
||||||
but the return code means that libcurl may have more data available to return
|
immediately, but the return code means that libcurl may have more data
|
||||||
or that there may be more data to send off before it is "satisfied".
|
available to return or that there may be more data to send off before it is
|
||||||
|
"satisfied".
|
||||||
|
|
||||||
In modern libcurls (from around 7.19.0 or later),
|
The return code from this function is for the whole multi stack. Problems
|
||||||
\fICURLM_CALL_MULTI_PERFORM\fP or \fICURLM_CALL_MULTI_SOKCET\fP will not be
|
still might have occurred on individual transfers even when one of these
|
||||||
returned and no application needs to care about them.
|
functions return OK.
|
||||||
|
|
||||||
NOTE that the return code from this function is for the whole multi stack.
|
|
||||||
Problems still might have occurred on individual transfers even when one of
|
|
||||||
these functions return OK.
|
|
||||||
.SH "TYPICAL USAGE"
|
.SH "TYPICAL USAGE"
|
||||||
1. Create a multi handle
|
1. Create a multi handle
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
.\" * | (__| |_| | _ <| |___
|
.\" * | (__| |_| | _ <| |___
|
||||||
.\" * \___|\___/|_| \_\_____|
|
.\" * \___|\___/|_| \_\_____|
|
||||||
.\" *
|
.\" *
|
||||||
.\" * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
|
.\" * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
.\" *
|
.\" *
|
||||||
.\" * This software is licensed as described in the file COPYING, which
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
.\" * you should have received as part of this distribution. The terms
|
.\" * you should have received as part of this distribution. The terms
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
.\" * $Id$
|
.\" * $Id$
|
||||||
.\" **************************************************************************
|
.\" **************************************************************************
|
||||||
.\"
|
.\"
|
||||||
.TH libcurl-errors 3 "8 Jun 2008" "libcurl 7.19.0" "libcurl errors"
|
.TH libcurl-errors 3 "1 Jan 2010" "libcurl 7.20.0" "libcurl errors"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
libcurl-errors \- error codes in libcurl
|
libcurl-errors \- error codes in libcurl
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
@@ -70,6 +70,11 @@ either a PASV or a EPSV command. The server is flawed.
|
|||||||
.IP "CURLE_FTP_WEIRD_227_FORMAT (14)"
|
.IP "CURLE_FTP_WEIRD_227_FORMAT (14)"
|
||||||
FTP servers return a 227-line as a response to a PASV command. If libcurl
|
FTP servers return a 227-line as a response to a PASV command. If libcurl
|
||||||
fails to parse that line, this return code is passed back.
|
fails to parse that line, this return code is passed back.
|
||||||
|
.IP "CURLE_FTP_PRET_FAILED (84)"
|
||||||
|
The FTP server does not understand the PRET command at all or does not support
|
||||||
|
the given argument. Be careful when using \fICURLOPT_CUSTOMREQUEST\fP, a
|
||||||
|
custom LIST command will be sent with PRET CMD before PASV as well. (Added in
|
||||||
|
7.20.0)
|
||||||
.IP "CURLE_FTP_CANT_GET_HOST (15)"
|
.IP "CURLE_FTP_CANT_GET_HOST (15)"
|
||||||
An internal failure to lookup the host used for the new connection.
|
An internal failure to lookup the host used for the new connection.
|
||||||
.IP "CURLE_FTP_COULDNT_SET_TYPE (17)"
|
.IP "CURLE_FTP_COULDNT_SET_TYPE (17)"
|
||||||
@@ -87,15 +92,13 @@ returned an error code that was 400 or higher (for FTP) or otherwise
|
|||||||
indicated unsuccessful completion of the command.
|
indicated unsuccessful completion of the command.
|
||||||
.IP "CURLE_HTTP_RETURNED_ERROR (22)"
|
.IP "CURLE_HTTP_RETURNED_ERROR (22)"
|
||||||
This is returned if CURLOPT_FAILONERROR is set TRUE and the HTTP server
|
This is returned if CURLOPT_FAILONERROR is set TRUE and the HTTP server
|
||||||
returns an error code that is >= 400. (This error code was formerly known as
|
returns an error code that is >= 400.
|
||||||
CURLE_HTTP_NOT_FOUND.)
|
|
||||||
.IP "CURLE_WRITE_ERROR (23)"
|
.IP "CURLE_WRITE_ERROR (23)"
|
||||||
An error occurred when writing received data to a local file, or an error was
|
An error occurred when writing received data to a local file, or an error was
|
||||||
returned to libcurl from a write callback.
|
returned to libcurl from a write callback.
|
||||||
.IP "CURLE_UPLOAD_FAILED (25)"
|
.IP "CURLE_UPLOAD_FAILED (25)"
|
||||||
Failed starting the upload. For FTP, the server typically denied the STOR
|
Failed starting the upload. For FTP, the server typically denied the STOR
|
||||||
command. The error buffer usually contains the server's explanation for this.
|
command. The error buffer usually contains the server's explanation for this.
|
||||||
(This error code was formerly known as CURLE_FTP_COULDNT_STOR_FILE.)
|
|
||||||
.IP "CURLE_READ_ERROR (26)"
|
.IP "CURLE_READ_ERROR (26)"
|
||||||
There was a problem reading a local file or an error returned by the read
|
There was a problem reading a local file or an error returned by the read
|
||||||
callback.
|
callback.
|
||||||
@@ -120,8 +123,9 @@ A problem occurred somewhere in the SSL/TLS handshake. You really want the
|
|||||||
error buffer and read the message there as it pinpoints the problem slightly
|
error buffer and read the message there as it pinpoints the problem slightly
|
||||||
more. Could be certificates (file formats, paths, permissions), passwords, and
|
more. Could be certificates (file formats, paths, permissions), passwords, and
|
||||||
others.
|
others.
|
||||||
.IP "CURLE_FTP_BAD_DOWNLOAD_RESUME (36)"
|
.IP "CURLE_BAD_DOWNLOAD_RESUME (36)"
|
||||||
Attempting FTP resume beyond file size.
|
The download could not be resumed because the specified offset was out of the
|
||||||
|
file boundary.
|
||||||
.IP "CURLE_FILE_COULDNT_READ_FILE (37)"
|
.IP "CURLE_FILE_COULDNT_READ_FILE (37)"
|
||||||
A file given with FILE:// couldn't be opened. Most likely because the file
|
A file given with FILE:// couldn't be opened. Most likely because the file
|
||||||
path doesn't identify an existing file. Did you check file permissions?
|
path doesn't identify an existing file. Did you check file permissions?
|
||||||
@@ -138,8 +142,7 @@ Internal error. A function was called with a bad parameter.
|
|||||||
.IP "CURLE_INTERFACE_FAILED (45)"
|
.IP "CURLE_INTERFACE_FAILED (45)"
|
||||||
Interface error. A specified outgoing interface could not be used. Set which
|
Interface error. A specified outgoing interface could not be used. Set which
|
||||||
interface to use for outgoing connections' source IP address with
|
interface to use for outgoing connections' source IP address with
|
||||||
CURLOPT_INTERFACE. (This error code was formerly known as
|
CURLOPT_INTERFACE.
|
||||||
CURLE_HTTP_PORT_FAILED.)
|
|
||||||
.IP "CURLE_TOO_MANY_REDIRECTS (47)"
|
.IP "CURLE_TOO_MANY_REDIRECTS (47)"
|
||||||
Too many redirects. When following redirects, libcurl hit the maximum amount.
|
Too many redirects. When following redirects, libcurl hit the maximum amount.
|
||||||
Set your limit with CURLOPT_MAXREDIRS.
|
Set your limit with CURLOPT_MAXREDIRS.
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG],
|
|||||||
AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
|
AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
|
||||||
AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
|
AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
|
||||||
AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
|
AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
|
||||||
|
AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
|
||||||
|
AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
|
||||||
|
AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
|
||||||
|
AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
|
||||||
|
|
||||||
AC_ARG_WITH(libcurl,
|
AC_ARG_WITH(libcurl,
|
||||||
AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
|
AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
|
||||||
@@ -194,17 +198,23 @@ x=CURLOPT_VERBOSE;
|
|||||||
|
|
||||||
# We don't have --protocols, so just assume that all
|
# We don't have --protocols, so just assume that all
|
||||||
# protocols are available
|
# protocols are available
|
||||||
_libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT"
|
_libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP
|
||||||
|
|
||||||
if test x$libcurl_feature_SSL = xyes ; then
|
if test x$libcurl_feature_SSL = xyes ; then
|
||||||
_libcurl_protocols="$_libcurl_protocols HTTPS"
|
_libcurl_protocols="$_libcurl_protocols HTTPS"
|
||||||
|
|
||||||
# FTPS wasn't standards-compliant until version
|
# FTPS wasn't standards-compliant until version
|
||||||
# 7.11.0
|
# 7.11.0 (0x070b00 == 461568)
|
||||||
if test $_libcurl_version -ge 461568; then
|
if test $_libcurl_version -ge 461568; then
|
||||||
_libcurl_protocols="$_libcurl_protocols FTPS"
|
_libcurl_protocols="$_libcurl_protocols FTPS"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# RTSP, IMAP, POP3 and SMTP were added in
|
||||||
|
# 7.20.0 (0x071400 == 463872)
|
||||||
|
if test $_libcurl_version -ge 463872; then
|
||||||
|
_libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for _libcurl_protocol in $_libcurl_protocols ; do
|
for _libcurl_protocol in $_libcurl_protocols ; do
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ CURLE_FAILED_INIT 7.1
|
|||||||
CURLE_FILESIZE_EXCEEDED 7.10.8
|
CURLE_FILESIZE_EXCEEDED 7.10.8
|
||||||
CURLE_FILE_COULDNT_READ_FILE 7.1
|
CURLE_FILE_COULDNT_READ_FILE 7.1
|
||||||
CURLE_FTP_ACCESS_DENIED 7.1
|
CURLE_FTP_ACCESS_DENIED 7.1
|
||||||
CURLE_FTP_BAD_DOWNLOAD_RESUME 7.1
|
CURLE_FTP_BAD_DOWNLOAD_RESUME 7.1 7.1
|
||||||
CURLE_FTP_CANT_GET_HOST 7.1
|
CURLE_FTP_CANT_GET_HOST 7.1
|
||||||
CURLE_FTP_CANT_RECONNECT 7.1 7.17.0
|
CURLE_FTP_CANT_RECONNECT 7.1 7.17.0
|
||||||
CURLE_FTP_COULDNT_GET_SIZE 7.1 7.17.0
|
CURLE_FTP_COULDNT_GET_SIZE 7.1 7.17.0
|
||||||
@@ -47,7 +47,9 @@ CURLE_FTP_COULDNT_SET_BINARY 7.1 7.17.0
|
|||||||
CURLE_FTP_COULDNT_SET_TYPE 7.17.0
|
CURLE_FTP_COULDNT_SET_TYPE 7.17.0
|
||||||
CURLE_FTP_COULDNT_STOR_FILE 7.1
|
CURLE_FTP_COULDNT_STOR_FILE 7.1
|
||||||
CURLE_FTP_COULDNT_USE_REST 7.1
|
CURLE_FTP_COULDNT_USE_REST 7.1
|
||||||
|
CURLE_FTP_PARTIAL_FILE 7.1 7.1
|
||||||
CURLE_FTP_PORT_FAILED 7.1
|
CURLE_FTP_PORT_FAILED 7.1
|
||||||
|
CURLE_FTP_PRET_FAILED 7.20.0
|
||||||
CURLE_FTP_QUOTE_ERROR 7.1 7.17.0
|
CURLE_FTP_QUOTE_ERROR 7.1 7.17.0
|
||||||
CURLE_FTP_SSL_FAILED - 7.17.0
|
CURLE_FTP_SSL_FAILED - 7.17.0
|
||||||
CURLE_FTP_USER_PASSWORD_INCORRECT 7.1 7.17.0
|
CURLE_FTP_USER_PASSWORD_INCORRECT 7.1 7.17.0
|
||||||
@@ -74,13 +76,15 @@ CURLE_OPERATION_TIMEDOUT 7.17.0
|
|||||||
CURLE_OPERATION_TIMEOUTED 7.1 7.17.0
|
CURLE_OPERATION_TIMEOUTED 7.1 7.17.0
|
||||||
CURLE_OUT_OF_MEMORY 7.1
|
CURLE_OUT_OF_MEMORY 7.1
|
||||||
CURLE_PARTIAL_FILE 7.1
|
CURLE_PARTIAL_FILE 7.1
|
||||||
CURLE_PEER_FAILED_VERIFICATION - 7.17.1
|
CURLE_PEER_FAILED_VERIFICATION 7.17.1
|
||||||
CURLE_QUOTE_ERROR 7.17.0
|
CURLE_QUOTE_ERROR 7.17.0
|
||||||
CURLE_RANGE_ERROR 7.17.0
|
CURLE_RANGE_ERROR 7.17.0
|
||||||
CURLE_READ_ERROR 7.1
|
CURLE_READ_ERROR 7.1
|
||||||
CURLE_RECV_ERROR 7.13.0
|
CURLE_RECV_ERROR 7.13.0
|
||||||
CURLE_REMOTE_ACCESS_DENIED 7.17.0
|
CURLE_REMOTE_ACCESS_DENIED 7.17.0
|
||||||
CURLE_REMOTE_DISK_FULL 7.17.0
|
CURLE_REMOTE_DISK_FULL 7.17.0
|
||||||
|
CURLE_RTSP_CSEQ_ERROR 7.20.0
|
||||||
|
CURLE_RTSP_SESSION_ERROR 7.20.0
|
||||||
CURLE_SEND_ERROR 7.13.0
|
CURLE_SEND_ERROR 7.13.0
|
||||||
CURLE_SHARE_IN_USE - 7.17.0
|
CURLE_SHARE_IN_USE - 7.17.0
|
||||||
CURLE_SSH 7.16.1
|
CURLE_SSH 7.16.1
|
||||||
@@ -93,7 +97,7 @@ CURLE_SSL_ENGINE_INITFAILED 7.13.0
|
|||||||
CURLE_SSL_ENGINE_NOTFOUND 7.9.3
|
CURLE_SSL_ENGINE_NOTFOUND 7.9.3
|
||||||
CURLE_SSL_ENGINE_SETFAILED 7.9.3
|
CURLE_SSL_ENGINE_SETFAILED 7.9.3
|
||||||
CURLE_SSL_ISSUER_ERROR 7.19.0
|
CURLE_SSL_ISSUER_ERROR 7.19.0
|
||||||
CURLE_SSL_PEER_CERTIFICATE 7.17.1
|
CURLE_SSL_PEER_CERTIFICATE - 7.17.1
|
||||||
CURLE_SSL_SHUTDOWN_FAILED 7.16.1
|
CURLE_SSL_SHUTDOWN_FAILED 7.16.1
|
||||||
CURLE_TELNET_OPTION_SYNTAX 7.7
|
CURLE_TELNET_OPTION_SYNTAX 7.7
|
||||||
CURLE_TFTP_DISKFULL 7.15.0 7.17.0
|
CURLE_TFTP_DISKFULL 7.15.0 7.17.0
|
||||||
@@ -231,7 +235,17 @@ CURLOPT_FTP_SSL 7.11.0 7.16.4
|
|||||||
CURLOPT_FTP_SSL_CCC 7.16.1
|
CURLOPT_FTP_SSL_CCC 7.16.1
|
||||||
CURLOPT_FTP_USE_EPRT 7.10.5
|
CURLOPT_FTP_USE_EPRT 7.10.5
|
||||||
CURLOPT_FTP_USE_EPSV 7.9.2
|
CURLOPT_FTP_USE_EPSV 7.9.2
|
||||||
|
CURLOPT_FTP_USE_PRET 7.20.0
|
||||||
|
CURLOPT_RTSP_REQUEST 7.20.0
|
||||||
|
CURLOPT_RTSP_SESSION_ID 7.20.0
|
||||||
|
CURLOPT_RTSP_STREAM_URI 7.20.0
|
||||||
|
CURLOPT_RTSP_TRANSPORT 7.20.0
|
||||||
|
CURLOPT_RTSP_CLIENT_CSEQ 7.20.0
|
||||||
|
CURLOPT_RTSP_SERVER_CSEQ 7.20.0
|
||||||
|
CURLOPT_INTERLEAVEDATA 7.20.0
|
||||||
|
CURLOPT_INTERLEAVEFUNCTION 7.20.0
|
||||||
CURLOPT_HEADER 7.1
|
CURLOPT_HEADER 7.1
|
||||||
|
CURLOPT_HEADERDATA 7.10
|
||||||
CURLOPT_HEADERFUNCTION 7.7.2
|
CURLOPT_HEADERFUNCTION 7.7.2
|
||||||
CURLOPT_HTTP200ALIASES 7.10.3
|
CURLOPT_HTTP200ALIASES 7.10.3
|
||||||
CURLOPT_HTTPAUTH 7.10.6
|
CURLOPT_HTTPAUTH 7.10.6
|
||||||
@@ -259,6 +273,8 @@ CURLOPT_LOCALPORT 7.15.2
|
|||||||
CURLOPT_LOCALPORTRANGE 7.15.2
|
CURLOPT_LOCALPORTRANGE 7.15.2
|
||||||
CURLOPT_LOW_SPEED_LIMIT 7.1
|
CURLOPT_LOW_SPEED_LIMIT 7.1
|
||||||
CURLOPT_LOW_SPEED_TIME 7.1
|
CURLOPT_LOW_SPEED_TIME 7.1
|
||||||
|
CURLOPT_MAIL_FROM 7.20.0
|
||||||
|
CURLOPT_MAIL_RCPT 7.20.0
|
||||||
CURLOPT_MAXCONNECTS 7.7
|
CURLOPT_MAXCONNECTS 7.7
|
||||||
CURLOPT_MAXFILESIZE 7.10.8
|
CURLOPT_MAXFILESIZE 7.10.8
|
||||||
CURLOPT_MAXFILESIZE_LARGE 7.11.0
|
CURLOPT_MAXFILESIZE_LARGE 7.11.0
|
||||||
@@ -374,10 +390,17 @@ CURLPROTO_FTP 7.19.4
|
|||||||
CURLPROTO_FTPS 7.19.4
|
CURLPROTO_FTPS 7.19.4
|
||||||
CURLPROTO_HTTP 7.19.4
|
CURLPROTO_HTTP 7.19.4
|
||||||
CURLPROTO_HTTPS 7.19.4
|
CURLPROTO_HTTPS 7.19.4
|
||||||
|
CURLPROTO_IMAP 7.20.0
|
||||||
|
CURLPROTO_IMAPS 7.20.0
|
||||||
CURLPROTO_LDAP 7.19.4
|
CURLPROTO_LDAP 7.19.4
|
||||||
CURLPROTO_LDAPS 7.19.4
|
CURLPROTO_LDAPS 7.19.4
|
||||||
|
CURLPROTO_POP3 7.20.0
|
||||||
|
CURLPROTO_POP3S 7.20.0
|
||||||
|
CURLPROTO_RTSP 7.20.0
|
||||||
CURLPROTO_SCP 7.19.4
|
CURLPROTO_SCP 7.19.4
|
||||||
CURLPROTO_SFTP 7.19.4
|
CURLPROTO_SFTP 7.19.4
|
||||||
|
CURLPROTO_SMTP 7.20.0
|
||||||
|
CURLPROTO_SMTPS 7.20.0
|
||||||
CURLPROTO_TELNET 7.19.4
|
CURLPROTO_TELNET 7.19.4
|
||||||
CURLPROTO_TFTP 7.19.4
|
CURLPROTO_TFTP 7.19.4
|
||||||
CURLPROXY_HTTP 7.10
|
CURLPROXY_HTTP 7.10
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -47,6 +47,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
|
||||||
|
/* Needed for __FreeBSD_version symbol definition */
|
||||||
|
#include <osreldate.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The include stuff here below is mainly for time_t! */
|
/* The include stuff here below is mainly for time_t! */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -66,7 +71,8 @@
|
|||||||
require it! */
|
require it! */
|
||||||
#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
|
#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
|
||||||
defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
|
defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
|
||||||
defined(ANDROID)
|
defined(ANDROID) || \
|
||||||
|
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -236,14 +242,6 @@ typedef curl_socket_t
|
|||||||
curlsocktype purpose,
|
curlsocktype purpose,
|
||||||
struct curl_sockaddr *address);
|
struct curl_sockaddr *address);
|
||||||
|
|
||||||
#ifndef CURL_NO_OLDIES
|
|
||||||
/* not used since 7.10.8, will be removed in a future release */
|
|
||||||
typedef int (*curl_passwd_callback)(void *clientp,
|
|
||||||
const char *prompt,
|
|
||||||
char *buffer,
|
|
||||||
int buflen);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CURLIOE_OK, /* I/O operation successful */
|
CURLIOE_OK, /* I/O operation successful */
|
||||||
CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
|
CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
|
||||||
@@ -407,6 +405,10 @@ typedef enum {
|
|||||||
wrong format (Added in 7.19.0) */
|
wrong format (Added in 7.19.0) */
|
||||||
CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
|
CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
|
||||||
7.19.0) */
|
7.19.0) */
|
||||||
|
CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */
|
||||||
|
CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */
|
||||||
|
CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Identifiers */
|
||||||
|
|
||||||
CURL_LAST /* never use! */
|
CURL_LAST /* never use! */
|
||||||
} CURLcode;
|
} CURLcode;
|
||||||
|
|
||||||
@@ -613,6 +615,13 @@ typedef enum {
|
|||||||
#define CURLPROTO_DICT (1<<9)
|
#define CURLPROTO_DICT (1<<9)
|
||||||
#define CURLPROTO_FILE (1<<10)
|
#define CURLPROTO_FILE (1<<10)
|
||||||
#define CURLPROTO_TFTP (1<<11)
|
#define CURLPROTO_TFTP (1<<11)
|
||||||
|
#define CURLPROTO_IMAP (1<<12)
|
||||||
|
#define CURLPROTO_IMAPS (1<<13)
|
||||||
|
#define CURLPROTO_POP3 (1<<14)
|
||||||
|
#define CURLPROTO_POP3S (1<<15)
|
||||||
|
#define CURLPROTO_SMTP (1<<16)
|
||||||
|
#define CURLPROTO_SMTPS (1<<17)
|
||||||
|
#define CURLPROTO_RTSP (1<<18)
|
||||||
#define CURLPROTO_ALL (~0) /* enable everything */
|
#define CURLPROTO_ALL (~0) /* enable everything */
|
||||||
|
|
||||||
/* long may be 32 or 64 bits, but we should never depend on anything else
|
/* long may be 32 or 64 bits, but we should never depend on anything else
|
||||||
@@ -1028,6 +1037,7 @@ typedef enum {
|
|||||||
essentially places a demand on the FTP server to acknowledge commands
|
essentially places a demand on the FTP server to acknowledge commands
|
||||||
in a timely manner. */
|
in a timely manner. */
|
||||||
CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
|
CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
|
||||||
|
#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
|
||||||
|
|
||||||
/* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
|
/* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
|
||||||
tell libcurl to resolve names to those IP versions only. This only has
|
tell libcurl to resolve names to those IP versions only. This only has
|
||||||
@@ -1272,6 +1282,39 @@ typedef enum {
|
|||||||
/* set the SSH host key callback custom pointer */
|
/* set the SSH host key callback custom pointer */
|
||||||
CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
|
CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
|
||||||
|
|
||||||
|
/* set the SMTP mail originator */
|
||||||
|
CINIT(MAIL_FROM, OBJECTPOINT, 186),
|
||||||
|
|
||||||
|
/* set the SMTP mail receiver(s) */
|
||||||
|
CINIT(MAIL_RCPT, OBJECTPOINT, 187),
|
||||||
|
|
||||||
|
/* FTP: send PRET before PASV */
|
||||||
|
CINIT(FTP_USE_PRET, LONG, 188),
|
||||||
|
|
||||||
|
/* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
|
||||||
|
CINIT(RTSP_REQUEST, LONG, 189),
|
||||||
|
|
||||||
|
/* The RTSP session identifier */
|
||||||
|
CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
|
||||||
|
|
||||||
|
/* The RTSP stream URI */
|
||||||
|
CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
|
||||||
|
|
||||||
|
/* The Transport: header to use in RTSP requests */
|
||||||
|
CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
|
||||||
|
|
||||||
|
/* Manually initialize the client RTSP CSeq for this handle */
|
||||||
|
CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
|
||||||
|
|
||||||
|
/* Manually initialize the server RTSP CSeq for this handle */
|
||||||
|
CINIT(RTSP_SERVER_CSEQ, LONG, 194),
|
||||||
|
|
||||||
|
/* The stream to pass to INTERLEAVEFUNCTION. */
|
||||||
|
CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
|
||||||
|
|
||||||
|
/* Let the application define a custom write method for RTP data */
|
||||||
|
CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
@@ -1315,6 +1358,7 @@ typedef enum {
|
|||||||
#define CURLOPT_WRITEDATA CURLOPT_FILE
|
#define CURLOPT_WRITEDATA CURLOPT_FILE
|
||||||
#define CURLOPT_READDATA CURLOPT_INFILE
|
#define CURLOPT_READDATA CURLOPT_INFILE
|
||||||
#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
|
#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
|
||||||
|
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
|
||||||
|
|
||||||
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
|
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
|
||||||
enum {
|
enum {
|
||||||
@@ -1327,6 +1371,25 @@ enum {
|
|||||||
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
|
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Public API enums for RTSP requests
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
CURL_RTSPREQ_NONE, /* first in list */
|
||||||
|
CURL_RTSPREQ_OPTIONS,
|
||||||
|
CURL_RTSPREQ_DESCRIBE,
|
||||||
|
CURL_RTSPREQ_ANNOUNCE,
|
||||||
|
CURL_RTSPREQ_SETUP,
|
||||||
|
CURL_RTSPREQ_PLAY,
|
||||||
|
CURL_RTSPREQ_PAUSE,
|
||||||
|
CURL_RTSPREQ_TEARDOWN,
|
||||||
|
CURL_RTSPREQ_GET_PARAMETER,
|
||||||
|
CURL_RTSPREQ_SET_PARAMETER,
|
||||||
|
CURL_RTSPREQ_RECORD,
|
||||||
|
CURL_RTSPREQ_RECEIVE,
|
||||||
|
CURL_RTSPREQ_LAST /* last in list */
|
||||||
|
};
|
||||||
|
|
||||||
/* These enums are for use with the CURLOPT_NETRC option. */
|
/* These enums are for use with the CURLOPT_NETRC option. */
|
||||||
enum CURL_NETRC_OPTION {
|
enum CURL_NETRC_OPTION {
|
||||||
CURL_NETRC_IGNORED, /* The .netrc will never be read.
|
CURL_NETRC_IGNORED, /* The .netrc will never be read.
|
||||||
@@ -1696,9 +1759,13 @@ typedef enum {
|
|||||||
CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33,
|
CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33,
|
||||||
CURLINFO_CERTINFO = CURLINFO_SLIST + 34,
|
CURLINFO_CERTINFO = CURLINFO_SLIST + 34,
|
||||||
CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35,
|
CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35,
|
||||||
|
CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36,
|
||||||
|
CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37,
|
||||||
|
CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38,
|
||||||
|
CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39,
|
||||||
/* Fill in new entries below here! */
|
/* Fill in new entries below here! */
|
||||||
|
|
||||||
CURLINFO_LASTONE = 35
|
CURLINFO_LASTONE = 39
|
||||||
} CURLINFO;
|
} CURLINFO;
|
||||||
|
|
||||||
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
|
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
|
||||||
|
|||||||
@@ -370,16 +370,7 @@
|
|||||||
# define CURL_SIZEOF_CURL_SOCKLEN_T 4
|
# define CURL_SIZEOF_CURL_SOCKLEN_T 4
|
||||||
|
|
||||||
#elif defined(__VMS)
|
#elif defined(__VMS)
|
||||||
# if defined(__alpha) || defined(__ia64)
|
# if defined(__VAX)
|
||||||
# define CURL_SIZEOF_LONG 4
|
|
||||||
# define CURL_TYPEOF_CURL_OFF_T long long
|
|
||||||
# define CURL_FORMAT_CURL_OFF_T "lld"
|
|
||||||
# define CURL_FORMAT_CURL_OFF_TU "llu"
|
|
||||||
# define CURL_FORMAT_OFF_T "%lld"
|
|
||||||
# define CURL_SIZEOF_CURL_OFF_T 8
|
|
||||||
# define CURL_SUFFIX_CURL_OFF_T LL
|
|
||||||
# define CURL_SUFFIX_CURL_OFF_TU ULL
|
|
||||||
# else
|
|
||||||
# define CURL_SIZEOF_LONG 4
|
# define CURL_SIZEOF_LONG 4
|
||||||
# define CURL_TYPEOF_CURL_OFF_T long
|
# define CURL_TYPEOF_CURL_OFF_T long
|
||||||
# define CURL_FORMAT_CURL_OFF_T "ld"
|
# define CURL_FORMAT_CURL_OFF_T "ld"
|
||||||
@@ -388,6 +379,15 @@
|
|||||||
# define CURL_SIZEOF_CURL_OFF_T 4
|
# define CURL_SIZEOF_CURL_OFF_T 4
|
||||||
# define CURL_SUFFIX_CURL_OFF_T L
|
# define CURL_SUFFIX_CURL_OFF_T L
|
||||||
# define CURL_SUFFIX_CURL_OFF_TU UL
|
# define CURL_SUFFIX_CURL_OFF_TU UL
|
||||||
|
# else
|
||||||
|
# define CURL_SIZEOF_LONG 4
|
||||||
|
# define CURL_TYPEOF_CURL_OFF_T long long
|
||||||
|
# define CURL_FORMAT_CURL_OFF_T "lld"
|
||||||
|
# define CURL_FORMAT_CURL_OFF_TU "llu"
|
||||||
|
# define CURL_FORMAT_OFF_T "%lld"
|
||||||
|
# define CURL_SIZEOF_CURL_OFF_T 8
|
||||||
|
# define CURL_SUFFIX_CURL_OFF_T LL
|
||||||
|
# define CURL_SUFFIX_CURL_OFF_TU ULL
|
||||||
# endif
|
# endif
|
||||||
# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
|
# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
|
||||||
# define CURL_SIZEOF_CURL_SOCKLEN_T 4
|
# define CURL_SIZEOF_CURL_SOCKLEN_T 4
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -246,4 +246,8 @@ typedef char
|
|||||||
#undef CURL_TYPEOF_CURL_SOCKLEN_T
|
#undef CURL_TYPEOF_CURL_SOCKLEN_T
|
||||||
#undef CURL_TYPEOF_CURL_OFF_T
|
#undef CURL_TYPEOF_CURL_OFF_T
|
||||||
|
|
||||||
|
#ifdef CURL_NO_OLDIES
|
||||||
|
#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __CURL_CURLRULES_H */
|
#endif /* __CURL_CURLRULES_H */
|
||||||
|
|||||||
@@ -31,13 +31,13 @@
|
|||||||
|
|
||||||
/* This is the version number of the libcurl package from which this header
|
/* This is the version number of the libcurl package from which this header
|
||||||
file origins: */
|
file origins: */
|
||||||
#define LIBCURL_VERSION "7.19.8-CVS"
|
#define LIBCURL_VERSION "7.20.0-CVS"
|
||||||
|
|
||||||
/* The numeric version number is also available "in parts" by using these
|
/* The numeric version number is also available "in parts" by using these
|
||||||
defines: */
|
defines: */
|
||||||
#define LIBCURL_VERSION_MAJOR 7
|
#define LIBCURL_VERSION_MAJOR 7
|
||||||
#define LIBCURL_VERSION_MINOR 19
|
#define LIBCURL_VERSION_MINOR 20
|
||||||
#define LIBCURL_VERSION_PATCH 8
|
#define LIBCURL_VERSION_PATCH 0
|
||||||
|
|
||||||
/* This is the numeric version of the libcurl version number, meant for easier
|
/* This is the numeric version of the libcurl version number, meant for easier
|
||||||
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
|
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
and it is always a greater number in a more recent release. It makes
|
and it is always a greater number in a more recent release. It makes
|
||||||
comparisons with greater than and less than work.
|
comparisons with greater than and less than work.
|
||||||
*/
|
*/
|
||||||
#define LIBCURL_VERSION_NUM 0x071308
|
#define LIBCURL_VERSION_NUM 0x071400
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the date and time when the full source package was created. The
|
* This is the date and time when the full source package was created. The
|
||||||
|
|||||||
@@ -39,38 +39,23 @@ C_ARG = $(OBJ_BASE)\wcc386.arg
|
|||||||
LINK_ARG = $(OBJ_BASE)\dyn\wlink.arg
|
LINK_ARG = $(OBJ_BASE)\dyn\wlink.arg
|
||||||
LIB_ARG = $(OBJ_BASE)\stat\wlib.arg
|
LIB_ARG = $(OBJ_BASE)\stat\wlib.arg
|
||||||
|
|
||||||
OBJS = $(OBJ_DIR)\base64.obj $(OBJ_DIR)\connect.obj &
|
# Unfortunately, we can't include Makefile.inc here because wmake doesn't
|
||||||
$(OBJ_DIR)\content_encoding.obj $(OBJ_DIR)\cookie.obj &
|
# use backslash as the line continuation character by default
|
||||||
$(OBJ_DIR)\curl_addrinfo.obj $(OBJ_DIR)\dict.obj &
|
CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c &
|
||||||
$(OBJ_DIR)\easy.obj $(OBJ_DIR)\escape.obj &
|
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c &
|
||||||
$(OBJ_DIR)\file.obj $(OBJ_DIR)\formdata.obj &
|
ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c &
|
||||||
$(OBJ_DIR)\ftp.obj $(OBJ_DIR)\getenv.obj &
|
netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c &
|
||||||
$(OBJ_DIR)\getinfo.obj $(OBJ_DIR)\gtls.obj &
|
krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c &
|
||||||
$(OBJ_DIR)\hash.obj $(OBJ_DIR)\hostares.obj &
|
multi.c content_encoding.c share.c http_digest.c md5.c curl_rand.c &
|
||||||
$(OBJ_DIR)\hostasyn.obj $(OBJ_DIR)\hostip.obj &
|
http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c &
|
||||||
$(OBJ_DIR)\hostip4.obj $(OBJ_DIR)\hostip6.obj &
|
hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c &
|
||||||
$(OBJ_DIR)\hostsyn.obj $(OBJ_DIR)\hostthre.obj &
|
inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c &
|
||||||
$(OBJ_DIR)\http.obj $(OBJ_DIR)\http_chunks.obj &
|
strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c &
|
||||||
$(OBJ_DIR)\http_digest.obj $(OBJ_DIR)\http_negotiate.obj &
|
socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c &
|
||||||
$(OBJ_DIR)\http_ntlm.obj $(OBJ_DIR)\if2ip.obj &
|
curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c
|
||||||
$(OBJ_DIR)\inet_ntop.obj $(OBJ_DIR)\inet_pton.obj &
|
|
||||||
$(OBJ_DIR)\krb4.obj $(OBJ_DIR)\ldap.obj &
|
OBJS = $(CSOURCES:.c=.obj)
|
||||||
$(OBJ_DIR)\llist.obj $(OBJ_DIR)\md5.obj &
|
OBJS = $OBJ_DIR\$(OBJS: = $OBJ_DIR\)
|
||||||
$(OBJ_DIR)\memdebug.obj $(OBJ_DIR)\mprintf.obj &
|
|
||||||
$(OBJ_DIR)\multi.obj $(OBJ_DIR)\netrc.obj &
|
|
||||||
$(OBJ_DIR)\parsedate.obj $(OBJ_DIR)\progress.obj &
|
|
||||||
$(OBJ_DIR)\security.obj $(OBJ_DIR)\rawstr.obj &
|
|
||||||
$(OBJ_DIR)\select.obj $(OBJ_DIR)\sendf.obj &
|
|
||||||
$(OBJ_DIR)\share.obj $(OBJ_DIR)\socks.obj &
|
|
||||||
$(OBJ_DIR)\speedcheck.obj $(OBJ_DIR)\splay.obj &
|
|
||||||
$(OBJ_DIR)\sslgen.obj $(OBJ_DIR)\ssluse.obj &
|
|
||||||
$(OBJ_DIR)\strequal.obj $(OBJ_DIR)\strerror.obj &
|
|
||||||
$(OBJ_DIR)\strtok.obj $(OBJ_DIR)\strtoofft.obj &
|
|
||||||
$(OBJ_DIR)\telnet.obj $(OBJ_DIR)\tftp.obj &
|
|
||||||
$(OBJ_DIR)\timeval.obj $(OBJ_DIR)\transfer.obj &
|
|
||||||
$(OBJ_DIR)\url.obj $(OBJ_DIR)\version.obj &
|
|
||||||
$(OBJ_DIR)\slist.obj $(OBJ_DIR)\nonblock.obj &
|
|
||||||
$(OBJ_DIR)\curl_rand.obj $(OBJ_DIR)\curl_memrchr.obj
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Use $(OBJS) as a template to generate $(OBJS_STAT) and $(OBJS_DYN).
|
# Use $(OBJS) as a template to generate $(OBJS_STAT) and $(OBJS_DYN).
|
||||||
@@ -554,3 +539,27 @@ $(OBJ_DIR)\curl_memrchr.obj: curl_memrchr.c setup.h config-win32.h &
|
|||||||
..\include\curl\curlrules.h ..\include\curl\easy.h &
|
..\include\curl\curlrules.h ..\include\curl\easy.h &
|
||||||
..\include\curl\multi.h ..\include\curl\curl.h curl_memrchr.h &
|
..\include\curl\multi.h ..\include\curl\curl.h curl_memrchr.h &
|
||||||
..\include\curl\mprintf.h curl_memory.h memdebug.h
|
..\include\curl\mprintf.h curl_memory.h memdebug.h
|
||||||
|
$(OBJ_DIR)\imap.obj: imap.c setup.h config-win32.h &
|
||||||
|
..\include\curl\curlbuild.h ..\include\curl\curlrules.h setup_once.h &
|
||||||
|
..\include\curl\curl.h ..\include\curl\curlver.h &
|
||||||
|
..\include\curl\curlrules.h ..\include\curl\easy.h &
|
||||||
|
..\include\curl\multi.h ..\include\curl\curl.h imap.h &
|
||||||
|
..\include\curl\mprintf.h curl_memory.h memdebug.h
|
||||||
|
$(OBJ_DIR)\pop3.obj: pop3.c setup.h config-win32.h &
|
||||||
|
..\include\curl\curlbuild.h ..\include\curl\curlrules.h setup_once.h &
|
||||||
|
..\include\curl\curl.h ..\include\curl\curlver.h &
|
||||||
|
..\include\curl\curlrules.h ..\include\curl\easy.h &
|
||||||
|
..\include\curl\multi.h ..\include\curl\curl.h pop3.h &
|
||||||
|
..\include\curl\mprintf.h curl_memory.h memdebug.h
|
||||||
|
$(OBJ_DIR)\smtp.obj: smtp.c setup.h config-win32.h &
|
||||||
|
..\include\curl\curlbuild.h ..\include\curl\curlrules.h setup_once.h &
|
||||||
|
..\include\curl\curl.h ..\include\curl\curlver.h &
|
||||||
|
..\include\curl\curlrules.h ..\include\curl\easy.h &
|
||||||
|
..\include\curl\multi.h ..\include\curl\curl.h smtp.h &
|
||||||
|
..\include\curl\mprintf.h curl_memory.h memdebug.h
|
||||||
|
$(OBJ_DIR)\pingpong.obj: pingpong.c setup.h config-win32.h &
|
||||||
|
..\include\curl\curlbuild.h ..\include\curl\curlrules.h setup_once.h &
|
||||||
|
..\include\curl\curl.h ..\include\curl\curlver.h &
|
||||||
|
..\include\curl\curlrules.h ..\include\curl\easy.h &
|
||||||
|
..\include\curl\multi.h ..\include\curl\curl.h pingpong.h &
|
||||||
|
..\include\curl\mprintf.h curl_memory.h memdebug.h
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
# | (__| |_| | _ <| |___
|
# | (__| |_| | _ <| |___
|
||||||
# \___|\___/|_| \_\_____|
|
# \___|\___/|_| \_\_____|
|
||||||
#
|
#
|
||||||
# Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
# Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
#
|
#
|
||||||
# This software is licensed as described in the file COPYING, which
|
# This software is licensed as described in the file COPYING, which
|
||||||
# you should have received as part of this distribution. The terms
|
# you should have received as part of this distribution. The terms
|
||||||
@@ -27,7 +27,7 @@ VCPROJ = libcurl.vcproj
|
|||||||
|
|
||||||
DOCS = README.encoding README.memoryleak README.ares README.curlx \
|
DOCS = README.encoding README.memoryleak README.ares README.curlx \
|
||||||
README.hostip README.multi_socket README.httpauth README.pipelining \
|
README.hostip README.multi_socket README.httpauth README.pipelining \
|
||||||
README.curl_off_t README.cmake
|
README.curl_off_t README.cmake README.pingpong
|
||||||
|
|
||||||
CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
|
CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
|
||||||
|
|
||||||
@@ -84,9 +84,9 @@ if SONAME_BUMP
|
|||||||
#
|
#
|
||||||
# This conditional soname bump SHOULD be removed at next "proper" bump.
|
# This conditional soname bump SHOULD be removed at next "proper" bump.
|
||||||
#
|
#
|
||||||
VERSIONINFO=-version-info 6:1:1
|
VERSIONINFO=-version-info 7:0:2
|
||||||
else
|
else
|
||||||
VERSIONINFO=-version-info 5:1:1
|
VERSIONINFO=-version-info 6:0:2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# This flag accepts an argument of the form current[:revision[:age]]. So,
|
# This flag accepts an argument of the form current[:revision[:age]]. So,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
|||||||
inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \
|
inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \
|
||||||
strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \
|
strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \
|
||||||
socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \
|
socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \
|
||||||
curl_memrchr.c
|
curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c
|
||||||
|
|
||||||
HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
|
HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
|
||||||
progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \
|
progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \
|
||||||
@@ -23,5 +23,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
|
|||||||
transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \
|
transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \
|
||||||
tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \
|
tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \
|
||||||
curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h \
|
curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h \
|
||||||
curl_memrchr.h
|
curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ objs = o.base64 o.connect o.cookie o.dict \
|
|||||||
o.strequal o.strtok o.telnet o.timeval \
|
o.strequal o.strtok o.telnet o.timeval \
|
||||||
o.transfer o.url o.version o.strtoofft o.sslgen o.gtls \
|
o.transfer o.url o.version o.strtoofft o.sslgen o.gtls \
|
||||||
o.rawstr o.curl_addrinfo o.slist o.nonblock o.curl_rand \
|
o.rawstr o.curl_addrinfo o.slist o.nonblock o.curl_rand \
|
||||||
o.curl_memrchr
|
o.curl_memrchr o.imap o.pop3 o.smtp o.pingpong o.rtsp \
|
||||||
|
o.curl_threads
|
||||||
|
|
||||||
|
|
||||||
# Compile options:
|
# Compile options:
|
||||||
@@ -44,6 +45,9 @@ o.curl_memrchr: c.curl_memrchr
|
|||||||
o.curl_rand: c.curl_rand
|
o.curl_rand: c.curl_rand
|
||||||
gcc $(compileropts) -c -o curl_rand.o c.curl_rand
|
gcc $(compileropts) -c -o curl_rand.o c.curl_rand
|
||||||
|
|
||||||
|
o.curl_threads: c.curl_threads
|
||||||
|
gcc $(compileropts) -c -o curl_threads.o c.curl_threads
|
||||||
|
|
||||||
o.dict: c.dict
|
o.dict: c.dict
|
||||||
gcc $(compileropts) -c -o dict.o c.dict
|
gcc $(compileropts) -c -o dict.o c.dict
|
||||||
|
|
||||||
@@ -92,6 +96,9 @@ o.http_chunks: c.http_chunks
|
|||||||
o.if2ip: c.if2ip
|
o.if2ip: c.if2ip
|
||||||
gcc $(compileropts) -c -o if2ip.o c.if2ip
|
gcc $(compileropts) -c -o if2ip.o c.if2ip
|
||||||
|
|
||||||
|
o.imap: c.imap
|
||||||
|
gcc $(compileropts) -c -o imap.o c.imap
|
||||||
|
|
||||||
o.inet_ntop: c.inet_ntop
|
o.inet_ntop: c.inet_ntop
|
||||||
gcc $(compileropts) -c -o inet_ntop.o c.inet_ntop
|
gcc $(compileropts) -c -o inet_ntop.o c.inet_ntop
|
||||||
|
|
||||||
@@ -116,9 +123,18 @@ o.netrc: c.netrc
|
|||||||
o.parsedate: c.parsedate
|
o.parsedate: c.parsedate
|
||||||
gcc $(compileropts) -c -o parsedate.o c.parsedate
|
gcc $(compileropts) -c -o parsedate.o c.parsedate
|
||||||
|
|
||||||
|
o.pingpong: c.pingpong
|
||||||
|
gcc $(compileropts) -c -o pingpong.o c.pingpong
|
||||||
|
|
||||||
|
o.pop3: c.pop3
|
||||||
|
gcc $(compileropts) -c -o pop3.o c.pop3
|
||||||
|
|
||||||
o.progress: c.progress
|
o.progress: c.progress
|
||||||
gcc $(compileropts) -c -o progress.o c.progress
|
gcc $(compileropts) -c -o progress.o c.progress
|
||||||
|
|
||||||
|
o.rtsp: c.rtsp
|
||||||
|
gcc $(compileropts) -c -o rtsp.o c.rtsp
|
||||||
|
|
||||||
o.security: c.security
|
o.security: c.security
|
||||||
gcc $(compileropts) -c -o security.o c.security
|
gcc $(compileropts) -c -o security.o c.security
|
||||||
|
|
||||||
@@ -131,6 +147,9 @@ o.sendf: c.sendf
|
|||||||
o.slist: c.slist
|
o.slist: c.slist
|
||||||
gcc $(compileropts) -c -o slist.o c.slist
|
gcc $(compileropts) -c -o slist.o c.slist
|
||||||
|
|
||||||
|
o.smtp: c.smtp
|
||||||
|
gcc $(compileropts) -c -o smtp.o c.smtp
|
||||||
|
|
||||||
o.speedcheck: c.speedcheck
|
o.speedcheck: c.speedcheck
|
||||||
gcc $(compileropts) -c -o speedcheck.o c.speedcheck
|
gcc $(compileropts) -c -o speedcheck.o c.speedcheck
|
||||||
|
|
||||||
|
|||||||
@@ -453,6 +453,7 @@ X_OBJS= \
|
|||||||
$(DIROBJ)\curl_memrchr.obj \
|
$(DIROBJ)\curl_memrchr.obj \
|
||||||
$(DIROBJ)\curl_rand.obj \
|
$(DIROBJ)\curl_rand.obj \
|
||||||
$(DIROBJ)\curl_sspi.obj \
|
$(DIROBJ)\curl_sspi.obj \
|
||||||
|
$(DIROBJ)\curl_threads.obj \
|
||||||
$(DIROBJ)\dict.obj \
|
$(DIROBJ)\dict.obj \
|
||||||
$(DIROBJ)\easy.obj \
|
$(DIROBJ)\easy.obj \
|
||||||
$(DIROBJ)\escape.obj \
|
$(DIROBJ)\escape.obj \
|
||||||
@@ -476,6 +477,7 @@ X_OBJS= \
|
|||||||
$(DIROBJ)\http_negotiate.obj \
|
$(DIROBJ)\http_negotiate.obj \
|
||||||
$(DIROBJ)\http_ntlm.obj \
|
$(DIROBJ)\http_ntlm.obj \
|
||||||
$(DIROBJ)\if2ip.obj \
|
$(DIROBJ)\if2ip.obj \
|
||||||
|
$(DIROBJ)\imap.obj \
|
||||||
$(DIROBJ)\inet_ntop.obj \
|
$(DIROBJ)\inet_ntop.obj \
|
||||||
$(DIROBJ)\inet_pton.obj \
|
$(DIROBJ)\inet_pton.obj \
|
||||||
$(DIROBJ)\ldap.obj \
|
$(DIROBJ)\ldap.obj \
|
||||||
@@ -487,12 +489,16 @@ X_OBJS= \
|
|||||||
$(DIROBJ)\netrc.obj \
|
$(DIROBJ)\netrc.obj \
|
||||||
$(DIROBJ)\nonblock.obj \
|
$(DIROBJ)\nonblock.obj \
|
||||||
$(DIROBJ)\parsedate.obj \
|
$(DIROBJ)\parsedate.obj \
|
||||||
|
$(DIROBJ)\pingpong.obj \
|
||||||
|
$(DIROBJ)\pop3.obj \
|
||||||
$(DIROBJ)\progress.obj \
|
$(DIROBJ)\progress.obj \
|
||||||
$(DIROBJ)\rawstr.obj \
|
$(DIROBJ)\rawstr.obj \
|
||||||
|
$(DIROBJ)\rtsp.obj \
|
||||||
$(DIROBJ)\select.obj \
|
$(DIROBJ)\select.obj \
|
||||||
$(DIROBJ)\sendf.obj \
|
$(DIROBJ)\sendf.obj \
|
||||||
$(DIROBJ)\share.obj \
|
$(DIROBJ)\share.obj \
|
||||||
$(DIROBJ)\slist.obj \
|
$(DIROBJ)\slist.obj \
|
||||||
|
$(DIROBJ)\smtp.obj \
|
||||||
$(DIROBJ)\socks.obj \
|
$(DIROBJ)\socks.obj \
|
||||||
$(DIROBJ)\socks_gssapi.obj \
|
$(DIROBJ)\socks_gssapi.obj \
|
||||||
$(DIROBJ)\socks_sspi.obj \
|
$(DIROBJ)\socks_sspi.obj \
|
||||||
|
|||||||
30
lib/README.pingpong
Normal file
30
lib/README.pingpong
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
Date: December 5, 2009
|
||||||
|
|
||||||
|
Pingpong
|
||||||
|
========
|
||||||
|
|
||||||
|
Pingpong is just my (Daniel's) jestful collective name on the protocols that
|
||||||
|
share a very similar kind of back-and-forth procedure with command and
|
||||||
|
responses to and from the server. FTP was previously the only protocol in
|
||||||
|
that family that libcurl supported, but when POP3, IMAP and SMTP joined the
|
||||||
|
team I moved some of the internals into a separate pingpong module to be
|
||||||
|
easier to get used by all these protocols to reduce code duplication and ease
|
||||||
|
code re-use between these protocols.
|
||||||
|
|
||||||
|
FTP
|
||||||
|
|
||||||
|
In 7.20.0 we converted code to use the new pingpong code from previously
|
||||||
|
having been all "native" FTP code.
|
||||||
|
|
||||||
|
POP3
|
||||||
|
|
||||||
|
There's no support in the documented URL format to specify the exact mail to
|
||||||
|
get, but we support that as the path specified in the URL.
|
||||||
|
|
||||||
|
IMAP
|
||||||
|
|
||||||
|
SMTP
|
||||||
|
|
||||||
|
There's no official URL syntax defined for SMTP, but we use only the generic
|
||||||
|
one and we provide two additional libcurl options to specify receivers and
|
||||||
|
sender of the actual mail.
|
||||||
@@ -458,14 +458,17 @@
|
|||||||
# if defined(__POCC__)
|
# if defined(__POCC__)
|
||||||
# define HAVE_FREEADDRINFO 1
|
# define HAVE_FREEADDRINFO 1
|
||||||
# define HAVE_GETADDRINFO 1
|
# define HAVE_GETADDRINFO 1
|
||||||
|
# define HAVE_GETADDRINFO_THREADSAFE 1
|
||||||
# define HAVE_GETNAMEINFO 1
|
# define HAVE_GETNAMEINFO 1
|
||||||
# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||||
# define HAVE_FREEADDRINFO 1
|
# define HAVE_FREEADDRINFO 1
|
||||||
# define HAVE_GETADDRINFO 1
|
# define HAVE_GETADDRINFO 1
|
||||||
|
# define HAVE_GETADDRINFO_THREADSAFE 1
|
||||||
# define HAVE_GETNAMEINFO 1
|
# define HAVE_GETNAMEINFO 1
|
||||||
# elif defined(_MSC_VER) && (_MSC_VER >= 1200)
|
# elif defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||||
# define HAVE_FREEADDRINFO 1
|
# define HAVE_FREEADDRINFO 1
|
||||||
# define HAVE_GETADDRINFO 1
|
# define HAVE_GETADDRINFO 1
|
||||||
|
# define HAVE_GETADDRINFO_THREADSAFE 1
|
||||||
# define HAVE_GETNAMEINFO 1
|
# define HAVE_GETNAMEINFO 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@@ -503,6 +506,24 @@
|
|||||||
# define USE_WIN32_SMALL_FILES
|
# define USE_WIN32_SMALL_FILES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
/* DNS RESOLVER SPECIALTY */
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Define USE_ARES to enable c-ares asynchronous DNS lookups */
|
||||||
|
/* #define USE_ARES 1 */
|
||||||
|
|
||||||
|
/* Define USE_THREADS_WIN32 to enable threaded asynchronous DNS lookups */
|
||||||
|
#define USE_THREADS_WIN32 1
|
||||||
|
|
||||||
|
#if defined(USE_ARES) && defined(USE_THREADS_WIN32)
|
||||||
|
# error "Only one DNS lookup specialty may be defined at most"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
/* LDAP SUPPORT */
|
/* LDAP SUPPORT */
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
#undef in_addr_t
|
#undef in_addr_t
|
||||||
#define in_addr_t unsigned long
|
#define in_addr_t unsigned long
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -89,6 +89,7 @@
|
|||||||
#include "inet_ntop.h"
|
#include "inet_ntop.h"
|
||||||
#include "inet_pton.h"
|
#include "inet_pton.h"
|
||||||
#include "sslgen.h" /* for Curl_ssl_check_cxn() */
|
#include "sslgen.h" /* for Curl_ssl_check_cxn() */
|
||||||
|
#include "progress.h"
|
||||||
|
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
@@ -192,7 +193,8 @@ long Curl_timeleft(struct connectdata *conn,
|
|||||||
#define WAITCONN_FDSET_ERROR 2
|
#define WAITCONN_FDSET_ERROR 2
|
||||||
|
|
||||||
static
|
static
|
||||||
int waitconnect(curl_socket_t sockfd, /* socket */
|
int waitconnect(struct connectdata *conn,
|
||||||
|
curl_socket_t sockfd, /* socket */
|
||||||
long timeout_msec)
|
long timeout_msec)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -203,21 +205,34 @@ int waitconnect(curl_socket_t sockfd, /* socket */
|
|||||||
(void)verifyconnect(sockfd, NULL);
|
(void)verifyconnect(sockfd, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
|
||||||
/* now select() until we get connect or timeout */
|
/* now select() until we get connect or timeout */
|
||||||
rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
|
rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)(timeout_msec>1000?
|
||||||
|
1000:timeout_msec));
|
||||||
|
|
||||||
|
if(Curl_pgrsUpdate(conn))
|
||||||
|
return CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
|
||||||
if(-1 == rc)
|
if(-1 == rc)
|
||||||
/* error, no connect here, try next */
|
/* error, no connect here, try next */
|
||||||
return WAITCONN_SELECT_ERROR;
|
return WAITCONN_SELECT_ERROR;
|
||||||
|
|
||||||
else if(0 == rc)
|
else if(0 == rc) {
|
||||||
/* timeout, no connect today */
|
/* timeout */
|
||||||
|
timeout_msec -= 1000;
|
||||||
|
if(timeout_msec <= 0)
|
||||||
return WAITCONN_TIMEOUT;
|
return WAITCONN_TIMEOUT;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(rc & CURL_CSELECT_ERR)
|
if(rc & CURL_CSELECT_ERR)
|
||||||
/* error condition caught */
|
/* error condition caught */
|
||||||
return WAITCONN_FDSET_ERROR;
|
return WAITCONN_FDSET_ERROR;
|
||||||
|
|
||||||
/* we have a connect! */
|
break;
|
||||||
|
}
|
||||||
return WAITCONN_CONNECTED;
|
return WAITCONN_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +385,7 @@ static CURLcode bindlocal(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
for(;;) {
|
||||||
if( bind(sockfd, sock, sizeof_sa) >= 0) {
|
if( bind(sockfd, sock, sizeof_sa) >= 0) {
|
||||||
/* we succeeded to bind */
|
/* we succeeded to bind */
|
||||||
struct Curl_sockaddr_storage add;
|
struct Curl_sockaddr_storage add;
|
||||||
@@ -382,13 +397,13 @@ static CURLcode bindlocal(struct connectdata *conn,
|
|||||||
error, Curl_strerror(conn, error));
|
error, Curl_strerror(conn, error));
|
||||||
return CURLE_INTERFACE_FAILED;
|
return CURLE_INTERFACE_FAILED;
|
||||||
}
|
}
|
||||||
infof(data, "Local port: %d\n", port);
|
infof(data, "Local port: %hu\n", port);
|
||||||
conn->bits.bound = TRUE;
|
conn->bits.bound = TRUE;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(--portnum > 0) {
|
if(--portnum > 0) {
|
||||||
infof(data, "Bind to local port %d failed, trying next\n", port);
|
infof(data, "Bind to local port %hu failed, trying next\n", port);
|
||||||
port++; /* try next port */
|
port++; /* try next port */
|
||||||
/* We re-use/clobber the port variable here below */
|
/* We re-use/clobber the port variable here below */
|
||||||
if(sock->sa_family == AF_INET)
|
if(sock->sa_family == AF_INET)
|
||||||
@@ -400,7 +415,7 @@ static CURLcode bindlocal(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
} while(1);
|
}
|
||||||
|
|
||||||
data->state.os_errno = error = SOCKERRNO;
|
data->state.os_errno = error = SOCKERRNO;
|
||||||
failf(data, "bind failed with errno %d: %s",
|
failf(data, "bind failed with errno %d: %s",
|
||||||
@@ -553,7 +568,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
|||||||
Curl_expire(data, allow);
|
Curl_expire(data, allow);
|
||||||
|
|
||||||
/* check for connect without timeout as we want to return immediately */
|
/* check for connect without timeout as we want to return immediately */
|
||||||
rc = waitconnect(sockfd, 0);
|
rc = waitconnect(conn, sockfd, 0);
|
||||||
|
|
||||||
if(WAITCONN_CONNECTED == rc) {
|
if(WAITCONN_CONNECTED == rc) {
|
||||||
int error;
|
int error;
|
||||||
@@ -566,7 +581,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
|||||||
data->state.os_errno = error;
|
data->state.os_errno = error;
|
||||||
infof(data, "Connection failed\n");
|
infof(data, "Connection failed\n");
|
||||||
if(trynextip(conn, sockindex, connected)) {
|
if(trynextip(conn, sockindex, connected)) {
|
||||||
failf(data, "Failed connect to %s:%d; %s",
|
failf(data, "Failed connect to %s:%ld; %s",
|
||||||
conn->host.name, conn->port, Curl_strerror(conn, error));
|
conn->host.name, conn->port, Curl_strerror(conn, error));
|
||||||
code = CURLE_COULDNT_CONNECT;
|
code = CURLE_COULDNT_CONNECT;
|
||||||
}
|
}
|
||||||
@@ -586,7 +601,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
|||||||
if(trynextip(conn, sockindex, connected)) {
|
if(trynextip(conn, sockindex, connected)) {
|
||||||
error = SOCKERRNO;
|
error = SOCKERRNO;
|
||||||
data->state.os_errno = error;
|
data->state.os_errno = error;
|
||||||
failf(data, "Failed connect to %s:%d; %s",
|
failf(data, "Failed connect to %s:%ld; %s",
|
||||||
conn->host.name, conn->port, Curl_strerror(conn, error));
|
conn->host.name, conn->port, Curl_strerror(conn, error));
|
||||||
code = CURLE_COULDNT_CONNECT;
|
code = CURLE_COULDNT_CONNECT;
|
||||||
}
|
}
|
||||||
@@ -719,12 +734,13 @@ singleipconnect(struct connectdata *conn,
|
|||||||
|
|
||||||
if(data->set.fopensocket)
|
if(data->set.fopensocket)
|
||||||
/*
|
/*
|
||||||
* If the opensocket callback is set, all the destination address information
|
* If the opensocket callback is set, all the destination address
|
||||||
* is passed to the callback. Depending on this information the callback may
|
* information is passed to the callback. Depending on this information the
|
||||||
* opt to abort the connection, this is indicated returning CURL_SOCKET_BAD;
|
* callback may opt to abort the connection, this is indicated returning
|
||||||
* otherwise it will return a not-connected socket. When the callback returns
|
* CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
|
||||||
* a valid socket the destination address information might have been changed
|
* the callback returns a valid socket the destination address information
|
||||||
* and this 'new' address will actually be used here to connect.
|
* might have been changed and this 'new' address will actually be used
|
||||||
|
* here to connect.
|
||||||
*/
|
*/
|
||||||
sockfd = data->set.fopensocket(data->set.opensocket_client,
|
sockfd = data->set.fopensocket(data->set.opensocket_client,
|
||||||
CURLSOCKTYPE_IPCXN,
|
CURLSOCKTYPE_IPCXN,
|
||||||
@@ -823,7 +839,7 @@ singleipconnect(struct connectdata *conn,
|
|||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
rc = waitconnect(sockfd, timeout_ms);
|
rc = waitconnect(conn, sockfd, timeout_ms);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* unknown error, fallthrough and try another address! */
|
/* unknown error, fallthrough and try another address! */
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
(doing so will reduce code size slightly). */
|
(doing so will reduce code size slightly). */
|
||||||
#define OLD_ZLIB_SUPPORT 1
|
#define OLD_ZLIB_SUPPORT 1
|
||||||
|
|
||||||
#define DSIZ 0x10000 /* buffer size for decompressed data */
|
#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
|
||||||
|
|
||||||
#define GZIP_MAGIC_0 0x1f
|
#define GZIP_MAGIC_0 0x1f
|
||||||
#define GZIP_MAGIC_1 0x8b
|
#define GZIP_MAGIC_1 0x8b
|
||||||
@@ -285,8 +285,8 @@ Curl_unencode_gzip_write(struct connectdata *conn,
|
|||||||
return process_zlib_error(conn, z);
|
return process_zlib_error(conn, z);
|
||||||
}
|
}
|
||||||
k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
|
k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
|
||||||
|
}
|
||||||
} else {
|
else {
|
||||||
/* we must parse the gzip header ourselves */
|
/* we must parse the gzip header ourselves */
|
||||||
if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
|
if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
|
||||||
return process_zlib_error(conn, z);
|
return process_zlib_error(conn, z);
|
||||||
|
|||||||
53
lib/cookie.c
53
lib/cookie.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -681,7 +681,8 @@ Curl_cookie_add(struct SessionHandle *data,
|
|||||||
|
|
||||||
if(c->running)
|
if(c->running)
|
||||||
/* Only show this when NOT reading the cookies from a file */
|
/* Only show this when NOT reading the cookies from a file */
|
||||||
infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
|
infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
|
||||||
|
"expire %" FORMAT_OFF_T "\n",
|
||||||
replace_old?"Replaced":"Added", co->name, co->value,
|
replace_old?"Replaced":"Added", co->name, co->value,
|
||||||
co->domain, co->path, co->expires);
|
co->domain, co->path, co->expires);
|
||||||
|
|
||||||
@@ -774,6 +775,18 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sort this so that the longest path gets before the shorter path */
|
||||||
|
static int cookie_sort(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
struct Cookie *c1 = *(struct Cookie **)p1;
|
||||||
|
struct Cookie *c2 = *(struct Cookie **)p2;
|
||||||
|
|
||||||
|
size_t l1 = c1->path?strlen(c1->path):0;
|
||||||
|
size_t l2 = c2->path?strlen(c2->path):0;
|
||||||
|
|
||||||
|
return (int)(l2 - l1);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* Curl_cookie_getlist()
|
* Curl_cookie_getlist()
|
||||||
@@ -794,6 +807,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
|||||||
struct Cookie *co;
|
struct Cookie *co;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
struct Cookie *mainco=NULL;
|
struct Cookie *mainco=NULL;
|
||||||
|
size_t matches = 0;
|
||||||
|
|
||||||
if(!c || !c->cookies)
|
if(!c || !c->cookies)
|
||||||
return NULL; /* no cookie struct or no cookies in the struct */
|
return NULL; /* no cookie struct or no cookies in the struct */
|
||||||
@@ -834,8 +848,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
|||||||
|
|
||||||
/* point the main to us */
|
/* point the main to us */
|
||||||
mainco = newco;
|
mainco = newco;
|
||||||
|
|
||||||
|
matches++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
fail:
|
||||||
/* failure, clear up the allocated chain and return NULL */
|
/* failure, clear up the allocated chain and return NULL */
|
||||||
while(mainco) {
|
while(mainco) {
|
||||||
co = mainco->next;
|
co = mainco->next;
|
||||||
@@ -851,6 +868,36 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
|||||||
co = co->next;
|
co = co->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(matches) {
|
||||||
|
/* Now we need to make sure that if there is a name appearing more than
|
||||||
|
once, the longest specified path version comes first. To make this
|
||||||
|
the swiftest way, we just sort them all based on path length. */
|
||||||
|
struct Cookie **array;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* alloc an array and store all cookie pointers */
|
||||||
|
array = (struct Cookie **)malloc(sizeof(struct Cookie *) * matches);
|
||||||
|
if(!array)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
co = mainco;
|
||||||
|
|
||||||
|
for(i=0; co; co = co->next)
|
||||||
|
array[i++] = co;
|
||||||
|
|
||||||
|
/* now sort the cookie pointers in path lenth order */
|
||||||
|
qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
|
||||||
|
|
||||||
|
/* remake the linked list order according to the new order */
|
||||||
|
|
||||||
|
mainco = array[0]; /* start here */
|
||||||
|
for(i=0; i<matches-1; i++)
|
||||||
|
array[i]->next = array[i+1];
|
||||||
|
array[matches-1]->next = NULL; /* terminate the list */
|
||||||
|
|
||||||
|
free(array); /* remove the temporary data again */
|
||||||
|
}
|
||||||
|
|
||||||
return mainco; /* return the new list */
|
return mainco; /* return the new list */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,7 +956,7 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies)
|
|||||||
{
|
{
|
||||||
struct Cookie *first, *curr, *next, *prev = NULL;
|
struct Cookie *first, *curr, *next, *prev = NULL;
|
||||||
|
|
||||||
if(!cookies->cookies || !cookies->cookies)
|
if(!cookies || !cookies->cookies)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
first = curr = prev = cookies->cookies;
|
first = curr = prev = cookies->cookies;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
# include <arpa/inet.h>
|
# include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
# include <in.h>
|
# include <in.h>
|
||||||
# include <inet.h>
|
# include <inet.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@@ -365,7 +365,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
|
|||||||
{
|
{
|
||||||
Curl_addrinfo *ai;
|
Curl_addrinfo *ai;
|
||||||
|
|
||||||
#if defined(VMS) && \
|
#if defined(__VMS) && \
|
||||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||||
#pragma pointer_size save
|
#pragma pointer_size save
|
||||||
#pragma pointer_size short
|
#pragma pointer_size short
|
||||||
@@ -418,7 +418,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
|
|||||||
h->h_addr_list[0] = addrentry;
|
h->h_addr_list[0] = addrentry;
|
||||||
h->h_addr_list[1] = NULL; /* terminate list of entries */
|
h->h_addr_list[1] = NULL; /* terminate list of entries */
|
||||||
|
|
||||||
#if defined(VMS) && \
|
#if defined(__VMS) && \
|
||||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||||
#pragma pointer_size restore
|
#pragma pointer_size restore
|
||||||
#pragma message enable PTRMISMATCH
|
#pragma message enable PTRMISMATCH
|
||||||
@@ -447,8 +447,7 @@ curl_dofreeaddrinfo(struct addrinfo *freethis,
|
|||||||
int line, const char *source)
|
int line, const char *source)
|
||||||
{
|
{
|
||||||
(freeaddrinfo)(freethis);
|
(freeaddrinfo)(freethis);
|
||||||
if(logfile)
|
curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
|
||||||
fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
|
|
||||||
source, line, (void *)freethis);
|
source, line, (void *)freethis);
|
||||||
}
|
}
|
||||||
#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
|
#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
|
||||||
@@ -471,17 +470,13 @@ curl_dogetaddrinfo(const char *hostname,
|
|||||||
int line, const char *source)
|
int line, const char *source)
|
||||||
{
|
{
|
||||||
int res=(getaddrinfo)(hostname, service, hints, result);
|
int res=(getaddrinfo)(hostname, service, hints, result);
|
||||||
if(0 == res) {
|
if(0 == res)
|
||||||
/* success */
|
/* success */
|
||||||
if(logfile)
|
curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
|
||||||
fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
|
|
||||||
source, line, (void *)*result);
|
source, line, (void *)*result);
|
||||||
}
|
else
|
||||||
else {
|
curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
|
||||||
if(logfile)
|
|
||||||
fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
|
|
||||||
source, line);
|
source, line);
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
|
#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
# include <arpa/inet.h>
|
# include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
# include <in.h>
|
# include <in.h>
|
||||||
# include <inet.h>
|
# include <inet.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
|
|||||||
128
lib/curl_threads.c
Normal file
128
lib/curl_threads.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2010, 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"
|
||||||
|
|
||||||
|
#if defined(USE_THREADS_POSIX)
|
||||||
|
# ifdef HAVE_PTHREAD_H
|
||||||
|
# include <pthread.h>
|
||||||
|
# endif
|
||||||
|
#elif defined(USE_THREADS_WIN32)
|
||||||
|
# ifdef HAVE_PROCESS_H
|
||||||
|
# include <process.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "curl_threads.h"
|
||||||
|
|
||||||
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "curl_memory.h"
|
||||||
|
/* The last #include file should be: */
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#if defined(USE_THREADS_POSIX)
|
||||||
|
|
||||||
|
struct curl_actual_call {
|
||||||
|
unsigned int (*func)(void *);
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *curl_thread_create_thunk(void *arg)
|
||||||
|
{
|
||||||
|
struct curl_actual_call * ac = arg;
|
||||||
|
unsigned int (*func)(void *) = ac->func;
|
||||||
|
void *real_arg = ac->arg;
|
||||||
|
|
||||||
|
free(ac);
|
||||||
|
|
||||||
|
(*func)(real_arg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_thread_t Curl_thread_create(unsigned int (*func) (void*), void *arg)
|
||||||
|
{
|
||||||
|
curl_thread_t t;
|
||||||
|
struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call));
|
||||||
|
if(!ac)
|
||||||
|
return curl_thread_t_null;
|
||||||
|
|
||||||
|
ac->func = func;
|
||||||
|
ac->arg = arg;
|
||||||
|
|
||||||
|
if(pthread_create(&t, NULL, curl_thread_create_thunk, ac) != 0) {
|
||||||
|
free(ac);
|
||||||
|
return curl_thread_t_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curl_thread_destroy(curl_thread_t hnd)
|
||||||
|
{
|
||||||
|
if(hnd != curl_thread_t_null)
|
||||||
|
pthread_detach(hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Curl_thread_join(curl_thread_t *hnd)
|
||||||
|
{
|
||||||
|
int ret = (pthread_join(*hnd, NULL) == 0);
|
||||||
|
|
||||||
|
*hnd = curl_thread_t_null;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(USE_THREADS_WIN32)
|
||||||
|
|
||||||
|
curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*), void *arg)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32_WCE
|
||||||
|
return CreateThread(NULL, 0, func, arg, 0, NULL);
|
||||||
|
#else
|
||||||
|
curl_thread_t t;
|
||||||
|
t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
|
||||||
|
if((t == 0) || (t == (curl_thread_t)-1L))
|
||||||
|
return curl_thread_t_null;
|
||||||
|
return t;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curl_thread_destroy(curl_thread_t hnd)
|
||||||
|
{
|
||||||
|
CloseHandle(hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Curl_thread_join(curl_thread_t *hnd)
|
||||||
|
{
|
||||||
|
int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
Curl_thread_destroy(*hnd);
|
||||||
|
|
||||||
|
*hnd = curl_thread_t_null;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_THREADS_* */
|
||||||
58
lib/curl_threads.h
Normal file
58
lib/curl_threads.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef HEADER_CURL_THREADS_H
|
||||||
|
#define HEADER_CURL_THREADS_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2010, 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"
|
||||||
|
|
||||||
|
#if defined(USE_THREADS_POSIX)
|
||||||
|
# define CURL_STDCALL
|
||||||
|
# define curl_mutex_t pthread_mutex_t
|
||||||
|
# define curl_thread_t pthread_t
|
||||||
|
# define curl_thread_t_null (pthread_t)0
|
||||||
|
# define Curl_mutex_init(m) pthread_mutex_init(m, NULL)
|
||||||
|
# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
|
||||||
|
# define Curl_mutex_release(m) pthread_mutex_unlock(m)
|
||||||
|
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
|
||||||
|
#elif defined(USE_THREADS_WIN32)
|
||||||
|
# define CURL_STDCALL __stdcall
|
||||||
|
# define curl_mutex_t CRITICAL_SECTION
|
||||||
|
# define curl_thread_t HANDLE
|
||||||
|
# define curl_thread_t_null (HANDLE)0
|
||||||
|
# define Curl_mutex_init(m) InitializeCriticalSection(m)
|
||||||
|
# define Curl_mutex_acquire(m) EnterCriticalSection(m)
|
||||||
|
# define Curl_mutex_release(m) LeaveCriticalSection(m)
|
||||||
|
# define Curl_mutex_destroy(m) DeleteCriticalSection(m)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
||||||
|
|
||||||
|
curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*),
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
void Curl_thread_destroy(curl_thread_t hnd);
|
||||||
|
|
||||||
|
int Curl_thread_join(curl_thread_t *hnd);
|
||||||
|
|
||||||
|
#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
|
||||||
|
|
||||||
|
#endif /* HEADER_CURL_THREADS_H */
|
||||||
20
lib/easy.c
20
lib/easy.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -882,11 +882,12 @@ CURLcode Curl_convert_to_network(struct SessionHandle *data,
|
|||||||
rc = data->set.convtonetwork(buffer, length);
|
rc = data->set.convtonetwork(buffer, length);
|
||||||
if(rc != CURLE_OK) {
|
if(rc != CURLE_OK) {
|
||||||
failf(data,
|
failf(data,
|
||||||
"CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
|
"CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
|
||||||
rc, curl_easy_strerror(rc));
|
(int)rc, curl_easy_strerror(rc));
|
||||||
}
|
}
|
||||||
return(rc);
|
return(rc);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
#ifdef HAVE_ICONV
|
#ifdef HAVE_ICONV
|
||||||
/* do the translation ourselves */
|
/* do the translation ourselves */
|
||||||
char *input_ptr, *output_ptr;
|
char *input_ptr, *output_ptr;
|
||||||
@@ -942,8 +943,8 @@ CURLcode Curl_convert_from_network(struct SessionHandle *data,
|
|||||||
rc = data->set.convfromnetwork(buffer, length);
|
rc = data->set.convfromnetwork(buffer, length);
|
||||||
if(rc != CURLE_OK) {
|
if(rc != CURLE_OK) {
|
||||||
failf(data,
|
failf(data,
|
||||||
"CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
|
"CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
|
||||||
rc, curl_easy_strerror(rc));
|
(int)rc, curl_easy_strerror(rc));
|
||||||
}
|
}
|
||||||
return(rc);
|
return(rc);
|
||||||
}
|
}
|
||||||
@@ -1003,11 +1004,12 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
|
|||||||
rc = data->set.convfromutf8(buffer, length);
|
rc = data->set.convfromutf8(buffer, length);
|
||||||
if(rc != CURLE_OK) {
|
if(rc != CURLE_OK) {
|
||||||
failf(data,
|
failf(data,
|
||||||
"CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
|
"CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
|
||||||
rc, curl_easy_strerror(rc));
|
(int)rc, curl_easy_strerror(rc));
|
||||||
}
|
}
|
||||||
return(rc);
|
return(rc);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
#ifdef HAVE_ICONV
|
#ifdef HAVE_ICONV
|
||||||
/* do the translation ourselves */
|
/* do the translation ourselves */
|
||||||
const char *input_ptr;
|
const char *input_ptr;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -103,7 +103,8 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength)
|
|||||||
if (Curl_isalnum(in)) {
|
if (Curl_isalnum(in)) {
|
||||||
/* just copy this */
|
/* just copy this */
|
||||||
ns[strindex++]=in;
|
ns[strindex++]=in;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
/* encode it */
|
/* encode it */
|
||||||
newlen += 2; /* the size grows with two, since this'll become a %XX */
|
newlen += 2; /* the size grows with two, since this'll become a %XX */
|
||||||
if(newlen > alloc) {
|
if(newlen > alloc) {
|
||||||
|
|||||||
14
lib/file.h
14
lib/file.h
@@ -8,7 +8,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -23,6 +23,18 @@
|
|||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* FILE unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
struct FILEPROTO {
|
||||||
|
char *path; /* the path we operate on */
|
||||||
|
char *freepath; /* pointer to the allocated block we must free, this might
|
||||||
|
differ from the 'path' pointer */
|
||||||
|
int fd; /* open file descriptor to read from! */
|
||||||
|
};
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_FILE
|
#ifndef CURL_DISABLE_FILE
|
||||||
extern const struct Curl_handler Curl_handler_file;
|
extern const struct Curl_handler Curl_handler_file;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -998,7 +998,8 @@ int curl_formget(struct curl_httppost *form, void *arg,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} while(nread == sizeof(buffer));
|
} while(nread == sizeof(buffer));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if(ptr->length != append(arg, ptr->line, ptr->length)) {
|
if(ptr->length != append(arg, ptr->line, ptr->length)) {
|
||||||
Curl_formclean(&data);
|
Curl_formclean(&data);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
121
lib/ftp.h
121
lib/ftp.h
@@ -1,5 +1,5 @@
|
|||||||
#ifndef __FTP_H
|
#ifndef HEADER_CURL_FTP_H
|
||||||
#define __FTP_H
|
#define HEADER_CURL_FTP_H
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* _ _ ____ _
|
* _ _ ____ _
|
||||||
* Project ___| | | | _ \| |
|
* Project ___| | | | _ \| |
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "pingpong.h"
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_FTP
|
#ifndef CURL_DISABLE_FTP
|
||||||
extern const struct Curl_handler Curl_handler_ftp;
|
extern const struct Curl_handler Curl_handler_ftp;
|
||||||
|
|
||||||
@@ -30,17 +32,110 @@ extern const struct Curl_handler Curl_handler_ftp;
|
|||||||
extern const struct Curl_handler Curl_handler_ftps;
|
extern const struct Curl_handler Curl_handler_ftps;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_HTTP
|
|
||||||
extern const struct Curl_handler Curl_handler_ftp_proxy;
|
|
||||||
|
|
||||||
# ifdef USE_SSL
|
|
||||||
extern const struct Curl_handler Curl_handler_ftps_proxy;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
|
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
|
||||||
CURLcode Curl_nbftpsendf(struct connectdata *, const char *fmt, ...);
|
|
||||||
CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
|
CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
|
||||||
int *ftpcode);
|
int *ftpcode);
|
||||||
#endif /* CURL_DISABLE_FTP */
|
#endif /* CURL_DISABLE_FTP */
|
||||||
#endif /* __FTP_H */
|
|
||||||
|
/****************************************************************************
|
||||||
|
* FTP unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
typedef enum {
|
||||||
|
FTP_STOP, /* do nothing state, stops the state machine */
|
||||||
|
FTP_WAIT220, /* waiting for the initial 220 response immediately after
|
||||||
|
a connect */
|
||||||
|
FTP_AUTH,
|
||||||
|
FTP_USER,
|
||||||
|
FTP_PASS,
|
||||||
|
FTP_ACCT,
|
||||||
|
FTP_PBSZ,
|
||||||
|
FTP_PROT,
|
||||||
|
FTP_CCC,
|
||||||
|
FTP_PWD,
|
||||||
|
FTP_SYST,
|
||||||
|
FTP_NAMEFMT,
|
||||||
|
FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
|
||||||
|
FTP_RETR_PREQUOTE,
|
||||||
|
FTP_STOR_PREQUOTE,
|
||||||
|
FTP_POSTQUOTE,
|
||||||
|
FTP_CWD, /* change dir */
|
||||||
|
FTP_MKD, /* if the dir didn't exist */
|
||||||
|
FTP_MDTM, /* to figure out the datestamp */
|
||||||
|
FTP_TYPE, /* to set type when doing a head-like request */
|
||||||
|
FTP_LIST_TYPE, /* set type when about to do a dir list */
|
||||||
|
FTP_RETR_TYPE, /* set type when about to RETR a file */
|
||||||
|
FTP_STOR_TYPE, /* set type when about to STOR a file */
|
||||||
|
FTP_SIZE, /* get the remote file's size for head-like request */
|
||||||
|
FTP_RETR_SIZE, /* get the remote file's size for RETR */
|
||||||
|
FTP_STOR_SIZE, /* get the size for (resumed) STOR */
|
||||||
|
FTP_REST, /* when used to check if the server supports it in head-like */
|
||||||
|
FTP_RETR_REST, /* when asking for "resume" in for RETR */
|
||||||
|
FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
|
||||||
|
FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */
|
||||||
|
FTP_PASV, /* generic state for PASV and EPSV, check count1 */
|
||||||
|
FTP_LIST, /* generic state for LIST, NLST or a custom list command */
|
||||||
|
FTP_RETR,
|
||||||
|
FTP_STOR, /* generic state for STOR and APPE */
|
||||||
|
FTP_QUIT,
|
||||||
|
FTP_LAST /* never used */
|
||||||
|
} ftpstate;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */
|
||||||
|
FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */
|
||||||
|
FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */
|
||||||
|
} curl_ftpfile;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FTPTRANSFER_BODY, /* yes do transfer a body */
|
||||||
|
FTPTRANSFER_INFO, /* do still go through to get info/headers */
|
||||||
|
FTPTRANSFER_NONE, /* don't get anything and don't get info */
|
||||||
|
FTPTRANSFER_LAST /* end of list marker, never used */
|
||||||
|
} curl_ftptransfer;
|
||||||
|
|
||||||
|
/* This FTP struct is used in the SessionHandle. All FTP data that is
|
||||||
|
connection-oriented must be in FTP_conn to properly deal with the fact that
|
||||||
|
perhaps the SessionHandle is changed between the times the connection is
|
||||||
|
used. */
|
||||||
|
struct FTP {
|
||||||
|
curl_off_t *bytecountp;
|
||||||
|
char *user; /* user name string */
|
||||||
|
char *passwd; /* password string */
|
||||||
|
|
||||||
|
/* transfer a file/body or not, done as a typedefed enum just to make
|
||||||
|
debuggers display the full symbol and not just the numerical value */
|
||||||
|
curl_ftptransfer transfer;
|
||||||
|
curl_off_t downloadsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ftp_conn is used for struct connection-oriented data in the connectdata
|
||||||
|
struct */
|
||||||
|
struct ftp_conn {
|
||||||
|
struct pingpong pp;
|
||||||
|
char *entrypath; /* the PWD reply when we logged on */
|
||||||
|
char **dirs; /* realloc()ed array for path components */
|
||||||
|
int dirdepth; /* number of entries used in the 'dirs' array */
|
||||||
|
int diralloc; /* number of entries allocated for the 'dirs' array */
|
||||||
|
char *file; /* decoded file */
|
||||||
|
bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
|
||||||
|
file size and 226/250 status check. It should still
|
||||||
|
read the line, just ignore the result. */
|
||||||
|
bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If
|
||||||
|
the connection has timed out or been closed, this
|
||||||
|
should be FALSE when it gets to Curl_ftp_quit() */
|
||||||
|
bool cwddone; /* if it has been determined that the proper CWD combo
|
||||||
|
already has been done */
|
||||||
|
bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent
|
||||||
|
caching the current directory */
|
||||||
|
char *prevpath; /* conn->path from the previous transfer */
|
||||||
|
char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
|
||||||
|
and others (A/I or zero) */
|
||||||
|
int count1; /* general purpose counter for the state machine */
|
||||||
|
int count2; /* general purpose counter for the state machine */
|
||||||
|
int count3; /* general purpose counter for the state machine */
|
||||||
|
ftpstate state; /* always use ftp.c:state() to change state! */
|
||||||
|
char * server_os; /* The target server operating system. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* HEADER_CURL_FTP_H */
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <unixlib.h>
|
#include <unixlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ char *GetEnv(const char *variable)
|
|||||||
return (env[0] != '\0')?strdup(env):NULL;
|
return (env[0] != '\0')?strdup(env):NULL;
|
||||||
#else
|
#else
|
||||||
char *env = getenv(variable);
|
char *env = getenv(variable);
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
if(env && strcmp("HOME",variable) == 0)
|
if(env && strcmp("HOME",variable) == 0)
|
||||||
env = decc_translate_vms(env);
|
env = decc_translate_vms(env);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -235,6 +235,19 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
|
|||||||
/* return if the condition prevented the document to get transfered */
|
/* return if the condition prevented the document to get transfered */
|
||||||
*param_longp = data->info.timecond;
|
*param_longp = data->info.timecond;
|
||||||
break;
|
break;
|
||||||
|
case CURLINFO_RTSP_SESSION_ID:
|
||||||
|
*param_charp = data->set.str[STRING_RTSP_SESSION_ID];
|
||||||
|
break;
|
||||||
|
case CURLINFO_RTSP_CLIENT_CSEQ:
|
||||||
|
*param_longp = data->state.rtsp_next_client_CSeq;
|
||||||
|
break;
|
||||||
|
case CURLINFO_RTSP_SERVER_CSEQ:
|
||||||
|
*param_longp = data->state.rtsp_next_server_CSeq;
|
||||||
|
break;
|
||||||
|
case CURLINFO_RTSP_CSEQ_RECV:
|
||||||
|
*param_longp = data->state.rtsp_CSeq_recv;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
#include "inet_pton.h"
|
#include "inet_pton.h"
|
||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
#include "select.h"
|
#include "select.h"
|
||||||
|
#include "progress.h"
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
@@ -119,7 +120,7 @@ int Curl_resolv_getsock(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ares_waitperform()
|
* waitperform()
|
||||||
*
|
*
|
||||||
* 1) Ask ares what sockets it currently plays with, then
|
* 1) Ask ares what sockets it currently plays with, then
|
||||||
* 2) wait for the timeout period to check for action on ares' sockets.
|
* 2) wait for the timeout period to check for action on ares' sockets.
|
||||||
@@ -128,7 +129,7 @@ int Curl_resolv_getsock(struct connectdata *conn,
|
|||||||
* return number of sockets it worked on
|
* return number of sockets it worked on
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ares_waitperform(struct connectdata *conn, int timeout_ms)
|
static int waitperform(struct connectdata *conn, int timeout_ms)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
int nfds;
|
int nfds;
|
||||||
@@ -192,7 +193,7 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
|
|||||||
|
|
||||||
*dns = NULL;
|
*dns = NULL;
|
||||||
|
|
||||||
ares_waitperform(conn, 0);
|
waitperform(conn, 0);
|
||||||
|
|
||||||
if(conn->async.done) {
|
if(conn->async.done) {
|
||||||
/* we're done, kill the ares handle */
|
/* we're done, kill the ares handle */
|
||||||
@@ -238,6 +239,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
|||||||
struct timeval *tvp, tv, store;
|
struct timeval *tvp, tv, store;
|
||||||
long timediff;
|
long timediff;
|
||||||
int itimeout;
|
int itimeout;
|
||||||
|
int timeout_ms;
|
||||||
|
|
||||||
itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
|
itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
|
||||||
|
|
||||||
@@ -246,14 +248,27 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
|||||||
|
|
||||||
tvp = ares_timeout(data->state.areschannel, &store, &tv);
|
tvp = ares_timeout(data->state.areschannel, &store, &tv);
|
||||||
|
|
||||||
/* use the timeout period ares returned to us above */
|
/* use the timeout period ares returned to us above if less than one
|
||||||
ares_waitperform(conn, (int)(tvp->tv_sec * 1000 + tvp->tv_usec/1000));
|
second is left, otherwise just use 1000ms to make sure the progress
|
||||||
|
callback gets called frequent enough */
|
||||||
|
if(!tvp->tv_sec)
|
||||||
|
timeout_ms = tvp->tv_usec/1000;
|
||||||
|
else
|
||||||
|
timeout_ms = 1000;
|
||||||
|
|
||||||
|
waitperform(conn, timeout_ms);
|
||||||
|
|
||||||
if(conn->async.done)
|
if(conn->async.done)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if(Curl_pgrsUpdate(conn)) {
|
||||||
|
rc = CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
timeout = -1; /* trigger the cancel below */
|
||||||
|
}
|
||||||
|
else {
|
||||||
timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
|
timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
|
||||||
timeout -= timediff?timediff:1; /* always deduct at least 1 */
|
timeout -= timediff?timediff:1; /* always deduct at least 1 */
|
||||||
|
}
|
||||||
if(timeout < 0) {
|
if(timeout < 0) {
|
||||||
/* our timeout, so we cancel the ares operation */
|
/* our timeout, so we cancel the ares operation */
|
||||||
ares_cancel(data->state.areschannel);
|
ares_cancel(data->state.areschannel);
|
||||||
@@ -270,14 +285,27 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
|||||||
if(!conn->async.dns) {
|
if(!conn->async.dns) {
|
||||||
/* a name was not resolved */
|
/* a name was not resolved */
|
||||||
if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
|
if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
|
||||||
|
if (conn->bits.httpproxy) {
|
||||||
|
failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname);
|
||||||
|
rc = CURLE_COULDNT_RESOLVE_PROXY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
failf(data, "Resolving host timed out: %s", conn->host.dispname);
|
failf(data, "Resolving host timed out: %s", conn->host.dispname);
|
||||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if(conn->async.done) {
|
else if(conn->async.done) {
|
||||||
|
if (conn->bits.httpproxy) {
|
||||||
|
failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname,
|
||||||
|
ares_strerror(conn->async.status));
|
||||||
|
rc = CURLE_COULDNT_RESOLVE_PROXY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
|
failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
|
||||||
ares_strerror(conn->async.status));
|
ares_strerror(conn->async.status));
|
||||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
rc = CURLE_OPERATION_TIMEDOUT;
|
rc = CURLE_OPERATION_TIMEDOUT;
|
||||||
|
|
||||||
@@ -289,6 +317,31 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ares_query_completed_cb() is the callback that ares will call when
|
||||||
|
* the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
|
||||||
|
* when using ares, is completed either successfully or with failure.
|
||||||
|
*/
|
||||||
|
static void ares_query_completed_cb(void *arg, /* (struct connectdata *) */
|
||||||
|
int status,
|
||||||
|
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
||||||
|
int timeouts,
|
||||||
|
#endif
|
||||||
|
struct hostent *hostent)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = (struct connectdata *)arg;
|
||||||
|
struct Curl_addrinfo * ai = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
||||||
|
(void)timeouts; /* ignored */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (status == CURL_ASYNC_SUCCESS) {
|
||||||
|
ai = Curl_he2ai(hostent, conn->async.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)Curl_addrinfo_callback(arg, status, ai);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_getaddrinfo() - when using ares
|
* Curl_getaddrinfo() - when using ares
|
||||||
@@ -310,7 +363,8 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
|
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
|
||||||
struct in6_addr in6;
|
struct in6_addr in6;
|
||||||
#endif /* CURLRES_IPV6 */
|
#endif /* CURLRES_IPV6 */
|
||||||
*waitp = FALSE;
|
|
||||||
|
*waitp = 0; /* default to synchronous response */
|
||||||
|
|
||||||
/* First check if this is an IPv4 address string */
|
/* First check if this is an IPv4 address string */
|
||||||
if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
|
if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
|
||||||
@@ -354,9 +408,9 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
|
|
||||||
/* areschannel is already setup in the Curl_open() function */
|
/* areschannel is already setup in the Curl_open() function */
|
||||||
ares_gethostbyname(data->state.areschannel, hostname, family,
|
ares_gethostbyname(data->state.areschannel, hostname, family,
|
||||||
(ares_host_callback)Curl_addrinfo4_callback, conn);
|
(ares_host_callback)ares_query_completed_cb, conn);
|
||||||
|
|
||||||
*waitp = TRUE; /* please wait for the response */
|
*waitp = 1; /* expect asynchronous response */
|
||||||
}
|
}
|
||||||
return NULL; /* no struct yet */
|
return NULL; /* no struct yet */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -72,38 +72,27 @@
|
|||||||
* Only for builds using asynchronous name resolves
|
* Only for builds using asynchronous name resolves
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifdef CURLRES_ASYNCH
|
#ifdef CURLRES_ASYNCH
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* addrinfo_callback() gets called by ares, gethostbyname_thread() or
|
* Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
|
||||||
* getaddrinfo_thread() when we got the name resolved (or not!).
|
* or getaddrinfo_thread() when we got the name resolved (or not!).
|
||||||
*
|
*
|
||||||
* If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the
|
* If the status argument is CURL_ASYNC_SUCCESS, this function takes
|
||||||
* address field since it might be freed when this function returns. This
|
* ownership of the Curl_addrinfo passed, storing the resolved data
|
||||||
* operation stores the resolved data in the DNS cache.
|
* in the DNS cache.
|
||||||
*
|
|
||||||
* NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same
|
|
||||||
* pointer it is given as argument!
|
|
||||||
*
|
*
|
||||||
* The storage operation locks and unlocks the DNS cache.
|
* The storage operation locks and unlocks the DNS cache.
|
||||||
*/
|
*/
|
||||||
static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */
|
CURLcode Curl_addrinfo_callback(struct connectdata * conn,
|
||||||
int status,
|
int status,
|
||||||
void *addr)
|
struct Curl_addrinfo *ai)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = (struct connectdata *)arg;
|
|
||||||
struct Curl_dns_entry *dns = NULL;
|
struct Curl_dns_entry *dns = NULL;
|
||||||
CURLcode rc = CURLE_OK;
|
CURLcode rc = CURLE_OK;
|
||||||
|
|
||||||
conn->async.status = status;
|
conn->async.status = status;
|
||||||
|
|
||||||
if(CURL_ASYNC_SUCCESS == status) {
|
if(CURL_ASYNC_SUCCESS == status) {
|
||||||
|
|
||||||
/*
|
|
||||||
* IPv4/ares: Curl_addrinfo_copy() copies the address and returns an
|
|
||||||
* allocated version.
|
|
||||||
*
|
|
||||||
* IPv6: Curl_addrinfo_copy() returns the input pointer!
|
|
||||||
*/
|
|
||||||
Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port);
|
|
||||||
if(ai) {
|
if(ai) {
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
@@ -138,35 +127,4 @@ static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
|
#endif /* CURLRES_ASYNCH */
|
||||||
int status,
|
|
||||||
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
|
||||||
int timeouts,
|
|
||||||
#endif
|
|
||||||
struct hostent *hostent)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
|
||||||
(void)timeouts; /* ignored */
|
|
||||||
#endif
|
|
||||||
return addrinfo_callback(arg, status, hostent);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CURLRES_IPV6
|
|
||||||
CURLcode Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
|
|
||||||
int status,
|
|
||||||
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
|
||||||
int timeouts,
|
|
||||||
#endif
|
|
||||||
Curl_addrinfo *ai)
|
|
||||||
{
|
|
||||||
/* NOTE: for CURLRES_ARES, the 'ai' argument is really a
|
|
||||||
* 'struct hostent' pointer.
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
|
||||||
(void)timeouts; /* ignored */
|
|
||||||
#endif
|
|
||||||
return addrinfo_callback(arg, status, ai);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* CURLRES_ASYNC */
|
|
||||||
|
|||||||
30
lib/hostip.c
30
lib/hostip.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -76,8 +76,8 @@
|
|||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
#if defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) \
|
#if defined(CURLRES_SYNCH) && \
|
||||||
&& !defined(USE_ARES)
|
defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
|
||||||
/* alarm-based timeouts can only be used with all the dependencies satisfied */
|
/* alarm-based timeouts can only be used with all the dependencies satisfied */
|
||||||
#define USE_ALARM_TIMEOUT
|
#define USE_ALARM_TIMEOUT
|
||||||
#endif
|
#endif
|
||||||
@@ -189,12 +189,14 @@ Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
|
|||||||
case AF_INET:
|
case AF_INET:
|
||||||
sa4 = (const void *)ai->ai_addr;
|
sa4 = (const void *)ai->ai_addr;
|
||||||
ipaddr4 = &sa4->sin_addr;
|
ipaddr4 = &sa4->sin_addr;
|
||||||
return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
|
return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
|
||||||
|
bufsize);
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
sa6 = (const void *)ai->ai_addr;
|
sa6 = (const void *)ai->ai_addr;
|
||||||
ipaddr6 = &sa6->sin6_addr;
|
ipaddr6 = &sa6->sin6_addr;
|
||||||
return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
|
return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
|
||||||
|
bufsize);
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -712,20 +714,4 @@ struct curl_hash *Curl_mk_dnscache(void)
|
|||||||
return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
|
return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CURLRES_ADDRINFO_COPY
|
|
||||||
|
|
||||||
/* align on even 64bit boundaries */
|
|
||||||
#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
|
|
||||||
* returns a pointer to the malloc()ed copy. You need to call free() on the
|
|
||||||
* returned buffer when you're done with it.
|
|
||||||
*/
|
|
||||||
Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
|
|
||||||
{
|
|
||||||
const struct hostent *orig = org;
|
|
||||||
|
|
||||||
return Curl_he2ai(orig, port);
|
|
||||||
}
|
|
||||||
#endif /* CURLRES_ADDRINFO_COPY */
|
|
||||||
|
|||||||
76
lib/hostip.h
76
lib/hostip.h
@@ -1,5 +1,5 @@
|
|||||||
#ifndef __HOSTIP_H
|
#ifndef HEADER_CURL_HOSTIP_H
|
||||||
#define __HOSTIP_H
|
#define HEADER_CURL_HOSTIP_H
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* _ _ ____ _
|
* _ _ ____ _
|
||||||
* Project ___| | | | _ \| |
|
* Project ___| | | | _ \| |
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -37,51 +37,13 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup comfortable CURLRES_* defines to use in the host*.c sources.
|
* Comfortable CURLRES_* definitions are included from setup.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef USE_ARES
|
#ifdef USE_ARES
|
||||||
#include <ares_version.h>
|
#include <ares_version.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ARES
|
|
||||||
#define CURLRES_ASYNCH
|
|
||||||
#define CURLRES_ARES
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_THREADING_GETHOSTBYNAME
|
|
||||||
#define CURLRES_ASYNCH
|
|
||||||
#define CURLRES_THREADED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_THREADING_GETADDRINFO
|
|
||||||
#define CURLRES_ASYNCH
|
|
||||||
#define CURLRES_THREADED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
#define CURLRES_IPV6
|
|
||||||
#else
|
|
||||||
#define CURLRES_IPV4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
|
|
||||||
#if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH)
|
|
||||||
/* If built for ipv4 and missing gethostbyname_r(), or if using async name
|
|
||||||
resolve, we need the Curl_addrinfo_copy() function (which itself needs the
|
|
||||||
Curl_he2ai() function)) */
|
|
||||||
#define CURLRES_ADDRINFO_COPY
|
|
||||||
#endif
|
|
||||||
#endif /* IPv4/ares-only */
|
|
||||||
|
|
||||||
#ifndef CURLRES_ASYNCH
|
|
||||||
#define CURLRES_SYNCH
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USE_LIBIDN
|
|
||||||
#define CURLRES_IDN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocate enough memory to hold the full name information structs and
|
/* Allocate enough memory to hold the full name information structs and
|
||||||
* everything. OSF1 is known to require at least 8872 bytes. The buffer
|
* everything. OSF1 is known to require at least 8872 bytes. The buffer
|
||||||
* required for storing all possible aliases and IP numbers is according to
|
* required for storing all possible aliases and IP numbers is according to
|
||||||
@@ -203,27 +165,19 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
|
|||||||
int line, const char *source);
|
int line, const char *source);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This is the callback function that is used when we build with asynch
|
/* IPv4 threadsafe resolve function used for synch and asynch builds */
|
||||||
resolve, ipv4 */
|
Curl_addrinfo *Curl_ipv4_resolve_r(const char * hostname, int port);
|
||||||
CURLcode Curl_addrinfo4_callback(void *arg,
|
|
||||||
|
/*
|
||||||
|
* Curl_addrinfo_callback() is used when we build with any asynch specialty.
|
||||||
|
* Handles end of async request processing. Inserts ai into hostcache when
|
||||||
|
* status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
|
||||||
|
* request completed wether successfull or failed.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_addrinfo_callback(struct connectdata *conn,
|
||||||
int status,
|
int status,
|
||||||
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
|
||||||
int timeouts,
|
|
||||||
#endif
|
|
||||||
struct hostent *hostent);
|
|
||||||
/* This is the callback function that is used when we build with asynch
|
|
||||||
resolve, ipv6 */
|
|
||||||
CURLcode Curl_addrinfo6_callback(void *arg,
|
|
||||||
int status,
|
|
||||||
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
|
|
||||||
int timeouts,
|
|
||||||
#endif
|
|
||||||
Curl_addrinfo *ai);
|
Curl_addrinfo *ai);
|
||||||
|
|
||||||
|
|
||||||
/* Clone a Curl_addrinfo struct, works protocol independently */
|
|
||||||
Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_printable_address() returns a printable version of the 1st address
|
* Curl_printable_address() returns a printable version of the 1st address
|
||||||
* given in the 'ip' argument. The result will be stored in the buf that is
|
* given in the 'ip' argument. The result will be stored in the buf that is
|
||||||
@@ -263,4 +217,4 @@ void Curl_destroy_thread_data(struct Curl_async *async);
|
|||||||
extern sigjmp_buf curl_jmpenv;
|
extern sigjmp_buf curl_jmpenv;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif /* HEADER_CURL_HOSTIP_H */
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -87,8 +87,7 @@ bool Curl_ipvalid(struct SessionHandle *data)
|
|||||||
return TRUE; /* OK, proceed */
|
return TRUE; /* OK, proceed */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
|
#ifdef CURLRES_SYNCH
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_getaddrinfo() - the ipv4 synchronous version.
|
* Curl_getaddrinfo() - the ipv4 synchronous version.
|
||||||
*
|
*
|
||||||
@@ -110,7 +109,34 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
int port,
|
int port,
|
||||||
int *waitp)
|
int *waitp)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_GETHOSTBYNAME_R_3)
|
Curl_addrinfo *ai = NULL;
|
||||||
|
|
||||||
|
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
||||||
|
(void)conn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*waitp = 0; /* synchronous response only */
|
||||||
|
|
||||||
|
ai = Curl_ipv4_resolve_r(hostname, port);
|
||||||
|
if(!ai)
|
||||||
|
infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
|
||||||
|
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
#endif /* CURLRES_SYNCH */
|
||||||
|
#endif /* CURLRES_IPV4 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
|
||||||
|
*
|
||||||
|
* This is used for both synchronous and asynchronous resolver builds,
|
||||||
|
* implying that only threadsafe code and function calls may be used.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
|
||||||
|
int port)
|
||||||
|
{
|
||||||
|
#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
|
||||||
int res;
|
int res;
|
||||||
#endif
|
#endif
|
||||||
Curl_addrinfo *ai = NULL;
|
Curl_addrinfo *ai = NULL;
|
||||||
@@ -118,17 +144,27 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
struct hostent *buf = NULL;
|
struct hostent *buf = NULL;
|
||||||
|
|
||||||
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
|
||||||
(void)conn;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*waitp = 0; /* don't wait, we act synchronously */
|
|
||||||
|
|
||||||
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
|
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
|
||||||
/* This is a dotted IP address 123.123.123.123-style */
|
/* This is a dotted IP address 123.123.123.123-style */
|
||||||
return Curl_ip2addr(AF_INET, &in, hostname, port);
|
return Curl_ip2addr(AF_INET, &in, hostname, port);
|
||||||
|
|
||||||
#if defined(HAVE_GETHOSTBYNAME_R)
|
#if defined(HAVE_GETADDRINFO_THREADSAFE)
|
||||||
|
else {
|
||||||
|
struct addrinfo hints;
|
||||||
|
char sbuf[NI_MAXSERV];
|
||||||
|
char *sbufptr = NULL;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = PF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
if(port) {
|
||||||
|
snprintf(sbuf, sizeof(sbuf), "%d", port);
|
||||||
|
sbufptr = sbuf;
|
||||||
|
}
|
||||||
|
hints.ai_flags = AI_CANONNAME;
|
||||||
|
(void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
|
||||||
|
|
||||||
|
#elif defined(HAVE_GETHOSTBYNAME_R)
|
||||||
/*
|
/*
|
||||||
* gethostbyname_r() is the preferred resolve function for many platforms.
|
* gethostbyname_r() is the preferred resolve function for many platforms.
|
||||||
* Since there are three different versions of it, the following code is
|
* Since there are three different versions of it, the following code is
|
||||||
@@ -146,7 +182,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
* platforms.
|
* platforms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_GETHOSTBYNAME_R_5
|
#if defined(HAVE_GETHOSTBYNAME_R_5)
|
||||||
/* Solaris, IRIX and more */
|
/* Solaris, IRIX and more */
|
||||||
h = gethostbyname_r(hostname,
|
h = gethostbyname_r(hostname,
|
||||||
(struct hostent *)buf,
|
(struct hostent *)buf,
|
||||||
@@ -164,8 +200,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif /* HAVE_GETHOSTBYNAME_R_5 */
|
#elif defined(HAVE_GETHOSTBYNAME_R_6)
|
||||||
#ifdef HAVE_GETHOSTBYNAME_R_6
|
|
||||||
/* Linux */
|
/* Linux */
|
||||||
|
|
||||||
(void)gethostbyname_r(hostname,
|
(void)gethostbyname_r(hostname,
|
||||||
@@ -206,8 +241,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if(!h) /* failure */
|
if(!h) /* failure */
|
||||||
#endif/* HAVE_GETHOSTBYNAME_R_6 */
|
#elif defined(HAVE_GETHOSTBYNAME_R_3)
|
||||||
#ifdef HAVE_GETHOSTBYNAME_R_3
|
|
||||||
/* AIX, Digital Unix/Tru64, HPUX 10, more? */
|
/* AIX, Digital Unix/Tru64, HPUX 10, more? */
|
||||||
|
|
||||||
/* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
|
/* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
|
||||||
@@ -259,26 +293,20 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif /* HAVE_GETHOSTBYNAME_R_3 */
|
#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
|
||||||
{
|
{
|
||||||
infof(conn->data, "gethostbyname_r(2) failed for %s\n", hostname);
|
|
||||||
h = NULL; /* set return code to NULL */
|
h = NULL; /* set return code to NULL */
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
#else /* HAVE_GETHOSTBYNAME_R */
|
#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
|
||||||
/*
|
/*
|
||||||
* Here is code for platforms that don't have gethostbyname_r() or for
|
* Here is code for platforms that don't have a thread safe
|
||||||
* which the gethostbyname() is the preferred() function.
|
* getaddrinfo() nor gethostbyname_r() function or for which
|
||||||
|
* gethostbyname() is the preferred one.
|
||||||
*/
|
*/
|
||||||
else {
|
else {
|
||||||
#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
|
h = gethostbyname((void*)hostname);
|
||||||
h = gethostbyname((char*)hostname);
|
#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
|
||||||
#else
|
|
||||||
h = gethostbyname(hostname);
|
|
||||||
#endif
|
|
||||||
if(!h)
|
|
||||||
infof(conn->data, "gethostbyname(2) failed for %s\n", hostname);
|
|
||||||
#endif /*HAVE_GETHOSTBYNAME_R */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(h) {
|
if(h) {
|
||||||
@@ -290,7 +318,3 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
|
|
||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CURLRES_SYNCH */
|
|
||||||
#endif /* CURLRES_IPV4 */
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -75,20 +75,6 @@
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifdef CURLRES_IPV6
|
#ifdef CURLRES_IPV6
|
||||||
|
|
||||||
#ifndef CURLRES_ARES
|
|
||||||
#ifdef CURLRES_ASYNCH
|
|
||||||
/*
|
|
||||||
* Curl_addrinfo_copy() is used by the asynch callback to copy a given
|
|
||||||
* address. But this is an ipv6 build and then we don't copy the address, we
|
|
||||||
* just return the same pointer!
|
|
||||||
*/
|
|
||||||
Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port)
|
|
||||||
{
|
|
||||||
(void) port;
|
|
||||||
return (Curl_addrinfo*)orig;
|
|
||||||
}
|
|
||||||
#endif /* CURLRES_ASYNCH */
|
|
||||||
#endif /* CURLRES_ARES */
|
|
||||||
|
|
||||||
#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
|
#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
|
||||||
/* These are strictly for memory tracing and are using the same style as the
|
/* These are strictly for memory tracing and are using the same style as the
|
||||||
@@ -112,17 +98,13 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
|
|||||||
host, hostlen,
|
host, hostlen,
|
||||||
serv, servlen,
|
serv, servlen,
|
||||||
flags);
|
flags);
|
||||||
if(0 == res) {
|
if(0 == res)
|
||||||
/* success */
|
/* success */
|
||||||
if(logfile)
|
curl_memlog("GETNAME %s:%d getnameinfo()\n",
|
||||||
fprintf(logfile, "GETNAME %s:%d getnameinfo()\n",
|
|
||||||
source, line);
|
source, line);
|
||||||
}
|
else
|
||||||
else {
|
curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
|
||||||
if(logfile)
|
|
||||||
fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n",
|
|
||||||
source, line, res);
|
source, line, res);
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
|
#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
|
||||||
@@ -144,7 +126,7 @@ bool Curl_ipvalid(struct SessionHandle *data)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES)
|
#if defined(CURLRES_SYNCH)
|
||||||
|
|
||||||
#ifdef DEBUG_ADDRINFO
|
#ifdef DEBUG_ADDRINFO
|
||||||
static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
|
static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
|
||||||
@@ -188,7 +170,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
int pf;
|
int pf;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
*waitp=0; /* don't wait, we have the response now */
|
*waitp = 0; /* synchronous response only */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if a limited name resolve has been requested.
|
* Check if a limited name resolve has been requested.
|
||||||
@@ -252,6 +234,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */
|
#endif /* CURLRES_SYNCH */
|
||||||
#endif /* ipv6 */
|
#endif /* CURLRES_IPV6 */
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
639
lib/hostthre.c
639
lib/hostthre.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -44,15 +44,21 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h> /* for the close() proto */
|
#include <unistd.h> /* for the close() proto */
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_THREADS_POSIX)
|
||||||
|
# ifdef HAVE_PTHREAD_H
|
||||||
|
# include <pthread.h>
|
||||||
|
# endif
|
||||||
|
#elif defined(USE_THREADS_WIN32)
|
||||||
# ifdef HAVE_PROCESS_H
|
# ifdef HAVE_PROCESS_H
|
||||||
# include <process.h>
|
# include <process.h>
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
|
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
|
||||||
#undef in_addr_t
|
#undef in_addr_t
|
||||||
@@ -68,22 +74,18 @@
|
|||||||
#include "url.h"
|
#include "url.h"
|
||||||
#include "multiif.h"
|
#include "multiif.h"
|
||||||
#include "inet_pton.h"
|
#include "inet_pton.h"
|
||||||
|
#include "inet_ntop.h"
|
||||||
|
#include "curl_threads.h"
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
#include "inet_ntop.h"
|
|
||||||
|
|
||||||
#include "curl_memory.h"
|
#include "curl_memory.h"
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#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
|
* Only for threaded name resolves builds
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifdef CURLRES_THREADED
|
#ifdef CURLRES_THREADED
|
||||||
|
|
||||||
@@ -92,249 +94,162 @@ static bool init_resolve_thread(struct connectdata *conn,
|
|||||||
const char *hostname, int port,
|
const char *hostname, int port,
|
||||||
const struct addrinfo *hints);
|
const struct addrinfo *hints);
|
||||||
|
|
||||||
#ifdef CURLRES_IPV4
|
|
||||||
#define THREAD_FUNC gethostbyname_thread
|
|
||||||
#define THREAD_NAME "gethostbyname_thread"
|
|
||||||
#else
|
|
||||||
#define THREAD_FUNC getaddrinfo_thread
|
|
||||||
#define THREAD_NAME "getaddrinfo_thread"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct thread_data {
|
/* Data for synchronization between resolver thread and its parent */
|
||||||
HANDLE thread_hnd;
|
struct thread_sync_data {
|
||||||
unsigned thread_id;
|
curl_mutex_t * mtx;
|
||||||
DWORD thread_status;
|
int done;
|
||||||
curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */
|
|
||||||
HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */
|
char * hostname; /* hostname to resolve, Curl_async.hostname
|
||||||
HANDLE event_resolved; /* marks that the thread obtained the information */
|
duplicate */
|
||||||
HANDLE event_thread_started; /* marks that the thread has initialized and
|
int port;
|
||||||
started */
|
int sock_error;
|
||||||
HANDLE mutex_terminate; /* serializes access to flag_terminate */
|
Curl_addrinfo *res;
|
||||||
HANDLE event_terminate; /* flag for thread to terminate instead of calling
|
#ifdef HAVE_GETADDRINFO
|
||||||
callbacks */
|
|
||||||
#ifdef CURLRES_IPV6
|
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Data for synchronization between resolver thread and its parent */
|
struct thread_data {
|
||||||
struct thread_sync_data {
|
curl_thread_t thread_hnd;
|
||||||
HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */
|
curl_socket_t dummy_sock;
|
||||||
HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
|
unsigned int poll_interval;
|
||||||
HANDLE event_terminate; /* thread_data.event_terminate duplicate */
|
int interval_end;
|
||||||
char * hostname; /* hostname to resolve, Curl_async.hostname
|
struct thread_sync_data tsd;
|
||||||
duplicate */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct thread_sync_data * conn_thread_sync_data(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
return &(((struct thread_data *)conn->async.os_specific)->tsd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
|
||||||
|
|
||||||
/* Destroy resolver thread synchronization data */
|
/* Destroy resolver thread synchronization data */
|
||||||
static
|
static
|
||||||
void destroy_thread_sync_data(struct thread_sync_data * tsd)
|
void destroy_thread_sync_data(struct thread_sync_data * tsd)
|
||||||
{
|
{
|
||||||
|
if (tsd->mtx) {
|
||||||
|
Curl_mutex_destroy(tsd->mtx);
|
||||||
|
free(tsd->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
if(tsd->hostname)
|
if(tsd->hostname)
|
||||||
free(tsd->hostname);
|
free(tsd->hostname);
|
||||||
if(tsd->event_terminate)
|
|
||||||
CloseHandle(tsd->event_terminate);
|
if (tsd->res)
|
||||||
if(tsd->mutex_terminate)
|
Curl_freeaddrinfo(tsd->res);
|
||||||
CloseHandle(tsd->mutex_terminate);
|
|
||||||
if(tsd->mutex_waiting)
|
|
||||||
CloseHandle(tsd->mutex_waiting);
|
|
||||||
memset(tsd,0,sizeof(*tsd));
|
memset(tsd,0,sizeof(*tsd));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize resolver thread synchronization data */
|
/* Initialize resolver thread synchronization data */
|
||||||
static
|
static
|
||||||
BOOL init_thread_sync_data(struct thread_data * td,
|
int init_thread_sync_data(struct thread_sync_data * tsd,
|
||||||
const char * hostname,
|
const char * hostname,
|
||||||
struct thread_sync_data * tsd)
|
int port,
|
||||||
|
const struct addrinfo *hints)
|
||||||
{
|
{
|
||||||
HANDLE curr_proc = GetCurrentProcess();
|
|
||||||
|
|
||||||
memset(tsd, 0, sizeof(*tsd));
|
memset(tsd, 0, sizeof(*tsd));
|
||||||
if(!DuplicateHandle(curr_proc, td->mutex_waiting,
|
|
||||||
curr_proc, &tsd->mutex_waiting, 0, FALSE,
|
tsd->port = port;
|
||||||
DUPLICATE_SAME_ACCESS)) {
|
#ifdef CURLRES_IPV6
|
||||||
/* failed to duplicate the mutex, no point in continuing */
|
DEBUGASSERT(hints);
|
||||||
destroy_thread_sync_data(tsd);
|
tsd->hints = *hints;
|
||||||
return FALSE;
|
#else
|
||||||
}
|
(void) hints;
|
||||||
if(!DuplicateHandle(curr_proc, td->mutex_terminate,
|
#endif
|
||||||
curr_proc, &tsd->mutex_terminate, 0, FALSE,
|
|
||||||
DUPLICATE_SAME_ACCESS)) {
|
tsd->mtx = malloc(sizeof(curl_mutex_t));
|
||||||
/* failed to duplicate the mutex, no point in continuing */
|
if (tsd->mtx == NULL) goto err_exit;
|
||||||
destroy_thread_sync_data(tsd);
|
|
||||||
return FALSE;
|
Curl_mutex_init(tsd->mtx);
|
||||||
}
|
|
||||||
if(!DuplicateHandle(curr_proc, td->event_terminate,
|
tsd->sock_error = CURL_ASYNC_SUCCESS;
|
||||||
curr_proc, &tsd->event_terminate, 0, FALSE,
|
|
||||||
DUPLICATE_SAME_ACCESS)) {
|
|
||||||
/* failed to duplicate the event, no point in continuing */
|
|
||||||
destroy_thread_sync_data(tsd);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* Copying hostname string because original can be destroyed by parent
|
/* Copying hostname string because original can be destroyed by parent
|
||||||
* thread during gethostbyname execution.
|
* thread during gethostbyname execution.
|
||||||
*/
|
*/
|
||||||
tsd->hostname = strdup(hostname);
|
tsd->hostname = strdup(hostname);
|
||||||
if(!tsd->hostname) {
|
if (!tsd->hostname) goto err_exit;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
err_exit:
|
||||||
/* Memory allocation failed */
|
/* Memory allocation failed */
|
||||||
destroy_thread_sync_data(tsd);
|
destroy_thread_sync_data(tsd);
|
||||||
return FALSE;
|
return 0;
|
||||||
}
|
}
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* acquire resolver thread synchronization */
|
|
||||||
static
|
|
||||||
BOOL acquire_thread_sync(struct thread_sync_data * tsd)
|
|
||||||
{
|
|
||||||
/* is the thread initiator still waiting for us ? */
|
|
||||||
if(WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
|
|
||||||
/* yes, it is */
|
|
||||||
|
|
||||||
/* Waiting access to event_terminate */
|
|
||||||
if(WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
|
|
||||||
/* Something went wrong - now just ignoring */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
|
|
||||||
/* Parent thread signaled us to terminate.
|
|
||||||
* This means that all data in conn->async is now destroyed
|
|
||||||
* and we cannot use it.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* release resolver thread synchronization */
|
|
||||||
static
|
|
||||||
void release_thread_sync(struct thread_sync_data * tsd)
|
|
||||||
{
|
|
||||||
ReleaseMutex(tsd->mutex_terminate);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CURLRES_IPV4)
|
|
||||||
/*
|
|
||||||
* gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
|
|
||||||
* and then exits.
|
|
||||||
*
|
|
||||||
* For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
|
|
||||||
* it.
|
|
||||||
*/
|
|
||||||
static unsigned __stdcall gethostbyname_thread (void *arg)
|
|
||||||
{
|
|
||||||
struct connectdata *conn = (struct connectdata*) arg;
|
|
||||||
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
|
|
||||||
struct hostent *he;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
/* Duplicate the passed mutex and event handles.
|
|
||||||
* This allows us to use it even after the container gets destroyed
|
|
||||||
* due to a resolver timeout.
|
|
||||||
*/
|
|
||||||
struct thread_sync_data tsd = { 0,0,0,NULL };
|
|
||||||
|
|
||||||
if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
|
|
||||||
/* thread synchronization data initialization failed */
|
|
||||||
return (unsigned)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->async.status = NO_DATA; /* pending status */
|
|
||||||
SET_SOCKERRNO(conn->async.status);
|
|
||||||
|
|
||||||
/* Signaling that we have initialized all copies of data and handles we
|
|
||||||
need */
|
|
||||||
SetEvent(td->event_thread_started);
|
|
||||||
|
|
||||||
he = gethostbyname (tsd.hostname);
|
|
||||||
|
|
||||||
/* is parent thread waiting for us and are we able to access conn members? */
|
|
||||||
if(acquire_thread_sync(&tsd)) {
|
|
||||||
/* Mark that we have obtained the information, and that we are calling
|
|
||||||
* back with it. */
|
|
||||||
SetEvent(td->event_resolved);
|
|
||||||
if(he) {
|
|
||||||
rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rc = Curl_addrinfo4_callback(conn, SOCKERRNO, NULL);
|
|
||||||
}
|
|
||||||
release_thread_sync(&tsd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
destroy_thread_sync_data(&tsd);
|
|
||||||
|
|
||||||
return (rc);
|
|
||||||
/* An implicit _endthreadex() here */
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(CURLRES_IPV6)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
|
* gethostbyname_thread() resolves a name and then exits.
|
||||||
* exits.
|
*/
|
||||||
|
static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
|
||||||
|
{
|
||||||
|
struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
|
||||||
|
|
||||||
|
tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
|
||||||
|
|
||||||
|
if (!tsd->res) {
|
||||||
|
tsd->sock_error = SOCKERRNO;
|
||||||
|
if (tsd->sock_error == 0)
|
||||||
|
tsd->sock_error = ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
Curl_mutex_acquire(tsd->mtx);
|
||||||
|
tsd->done = 1;
|
||||||
|
Curl_mutex_release(tsd->mtx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getaddrinfo_complete(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct thread_sync_data *tsd = conn_thread_sync_data(conn);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
|
||||||
|
/* The tsd->res structure has been copied to async.dns and perhaps the DNS cache.
|
||||||
|
Set our copy to NULL so destroy_thread_sync_data doesn't free it.
|
||||||
|
*/
|
||||||
|
tsd->res = NULL;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_GETADDRINFO)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getaddrinfo_thread() resolves a name and then exits.
|
||||||
*
|
*
|
||||||
* For builds without ARES, but with ENABLE_IPV6, create a resolver thread
|
* For builds without ARES, but with ENABLE_IPV6, create a resolver thread
|
||||||
* and wait on it.
|
* and wait on it.
|
||||||
*/
|
*/
|
||||||
static unsigned __stdcall getaddrinfo_thread (void *arg)
|
static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = (struct connectdata*) arg;
|
struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
|
||||||
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
|
|
||||||
Curl_addrinfo *res;
|
|
||||||
char service [NI_MAXSERV];
|
char service [NI_MAXSERV];
|
||||||
int rc;
|
int rc;
|
||||||
struct addrinfo hints = td->hints;
|
|
||||||
|
|
||||||
/* Duplicate the passed mutex handle.
|
snprintf(service, sizeof(service), "%d", tsd->port);
|
||||||
* This allows us to use it even after the container gets destroyed
|
|
||||||
* due to a resolver timeout.
|
|
||||||
*/
|
|
||||||
struct thread_sync_data tsd = { 0,0,0,NULL };
|
|
||||||
|
|
||||||
if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
|
rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
|
||||||
/* thread synchronization data initialization failed */
|
|
||||||
return -1;
|
if (rc != 0) {
|
||||||
|
tsd->sock_error = SOCKERRNO;
|
||||||
|
if (tsd->sock_error == 0)
|
||||||
|
tsd->sock_error = ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
itoa(conn->async.port, service, 10);
|
Curl_mutex_acquire(tsd->mtx);
|
||||||
|
tsd->done = 1;
|
||||||
|
Curl_mutex_release(tsd->mtx);
|
||||||
|
|
||||||
conn->async.status = NO_DATA; /* pending status */
|
return 0;
|
||||||
SET_SOCKERRNO(conn->async.status);
|
|
||||||
|
|
||||||
/* Signaling that we have initialized all copies of data and handles we
|
|
||||||
need */
|
|
||||||
SetEvent(td->event_thread_started);
|
|
||||||
|
|
||||||
rc = Curl_getaddrinfo_ex(tsd.hostname, service, &hints, &res);
|
|
||||||
|
|
||||||
/* is parent thread waiting for us and are we able to access conn members? */
|
|
||||||
if(acquire_thread_sync(&tsd)) {
|
|
||||||
/* Mark that we have obtained the information, and that we are calling
|
|
||||||
back with it. */
|
|
||||||
SetEvent(td->event_resolved);
|
|
||||||
|
|
||||||
if(rc == 0) {
|
|
||||||
rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rc = Curl_addrinfo6_callback(conn, SOCKERRNO, NULL);
|
|
||||||
}
|
|
||||||
release_thread_sync(&tsd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clean up */
|
#endif /* HAVE_GETADDRINFO */
|
||||||
destroy_thread_sync_data(&tsd);
|
|
||||||
|
|
||||||
return (rc);
|
|
||||||
/* An implicit _endthreadex() here */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_destroy_thread_data() cleans up async resolver data and thread handle.
|
* Curl_destroy_thread_data() cleans up async resolver data and thread handle.
|
||||||
@@ -347,38 +262,14 @@ void Curl_destroy_thread_data (struct Curl_async *async)
|
|||||||
|
|
||||||
if(async->os_specific) {
|
if(async->os_specific) {
|
||||||
struct thread_data *td = (struct thread_data*) async->os_specific;
|
struct thread_data *td = (struct thread_data*) async->os_specific;
|
||||||
curl_socket_t sock = td->dummy_sock;
|
|
||||||
|
|
||||||
if(td->mutex_terminate && td->event_terminate) {
|
if (td->dummy_sock != CURL_SOCKET_BAD)
|
||||||
/* Signaling resolver thread to terminate */
|
sclose(td->dummy_sock);
|
||||||
if(WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
|
|
||||||
SetEvent(td->event_terminate);
|
|
||||||
ReleaseMutex(td->mutex_terminate);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Something went wrong - just ignoring it */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(td->mutex_terminate)
|
if (td->thread_hnd != curl_thread_t_null)
|
||||||
CloseHandle(td->mutex_terminate);
|
Curl_thread_join(&td->thread_hnd);
|
||||||
if(td->event_terminate)
|
|
||||||
CloseHandle(td->event_terminate);
|
|
||||||
if(td->event_thread_started)
|
|
||||||
CloseHandle(td->event_thread_started);
|
|
||||||
|
|
||||||
if(sock != CURL_SOCKET_BAD)
|
destroy_thread_sync_data(&td->tsd);
|
||||||
sclose(sock);
|
|
||||||
|
|
||||||
/* destroy the synchronization objects */
|
|
||||||
if(td->mutex_waiting)
|
|
||||||
CloseHandle(td->mutex_waiting);
|
|
||||||
td->mutex_waiting = NULL;
|
|
||||||
if(td->event_resolved)
|
|
||||||
CloseHandle(td->event_resolved);
|
|
||||||
|
|
||||||
if(td->thread_hnd)
|
|
||||||
CloseHandle(td->thread_hnd);
|
|
||||||
|
|
||||||
free(async->os_specific);
|
free(async->os_specific);
|
||||||
}
|
}
|
||||||
@@ -397,114 +288,58 @@ static bool init_resolve_thread (struct connectdata *conn,
|
|||||||
const struct addrinfo *hints)
|
const struct addrinfo *hints)
|
||||||
{
|
{
|
||||||
struct thread_data *td = calloc(1, sizeof(struct thread_data));
|
struct thread_data *td = calloc(1, sizeof(struct thread_data));
|
||||||
HANDLE thread_and_event[2] = {0};
|
int err = ENOMEM;
|
||||||
|
|
||||||
if(!td) {
|
conn->async.os_specific = (void*) td;
|
||||||
SET_ERRNO(ENOMEM);
|
if(!td)
|
||||||
return FALSE;
|
goto err_exit;
|
||||||
}
|
|
||||||
|
|
||||||
Curl_safefree(conn->async.hostname);
|
|
||||||
conn->async.hostname = strdup(hostname);
|
|
||||||
if(!conn->async.hostname) {
|
|
||||||
free(td);
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->async.port = port;
|
conn->async.port = port;
|
||||||
conn->async.done = FALSE;
|
conn->async.done = FALSE;
|
||||||
conn->async.status = 0;
|
conn->async.status = 0;
|
||||||
conn->async.dns = NULL;
|
conn->async.dns = NULL;
|
||||||
conn->async.os_specific = (void*) td;
|
|
||||||
td->dummy_sock = CURL_SOCKET_BAD;
|
td->dummy_sock = CURL_SOCKET_BAD;
|
||||||
|
td->thread_hnd = curl_thread_t_null;
|
||||||
|
|
||||||
/* Create the mutex used to inform the resolver thread that we're
|
if (!init_thread_sync_data(&td->tsd, hostname, port, hints))
|
||||||
* still waiting, and take initial ownership.
|
goto err_exit;
|
||||||
*/
|
|
||||||
td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
|
|
||||||
if(td->mutex_waiting == NULL) {
|
|
||||||
Curl_destroy_thread_data(&conn->async);
|
|
||||||
SET_ERRNO(EAGAIN);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the event that the thread uses to inform us that it's
|
Curl_safefree(conn->async.hostname);
|
||||||
* done resolving. Do not signal it.
|
conn->async.hostname = strdup(hostname);
|
||||||
*/
|
if(!conn->async.hostname)
|
||||||
td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
|
goto err_exit;
|
||||||
if(td->event_resolved == NULL) {
|
|
||||||
Curl_destroy_thread_data(&conn->async);
|
|
||||||
SET_ERRNO(EAGAIN);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* Create the mutex used to serialize access to event_terminated
|
|
||||||
* between us and resolver thread.
|
|
||||||
*/
|
|
||||||
td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
|
|
||||||
if(td->mutex_terminate == NULL) {
|
|
||||||
Curl_destroy_thread_data(&conn->async);
|
|
||||||
SET_ERRNO(EAGAIN);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* Create the event used to signal thread that it should terminate.
|
|
||||||
*/
|
|
||||||
td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
if(td->event_terminate == NULL) {
|
|
||||||
Curl_destroy_thread_data(&conn->async);
|
|
||||||
SET_ERRNO(EAGAIN);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* Create the event used by thread to inform it has initialized its own data.
|
|
||||||
*/
|
|
||||||
td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
if(td->event_thread_started == NULL) {
|
|
||||||
Curl_destroy_thread_data(&conn->async);
|
|
||||||
SET_ERRNO(EAGAIN);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32_WCE
|
#ifdef WIN32
|
||||||
td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
|
/* This socket is only to keep Curl_resolv_fdset() and select() happy;
|
||||||
(LPTHREAD_START_ROUTINE) THREAD_FUNC,
|
* should never become signalled for read since it's unbound but
|
||||||
conn, 0, &td->thread_id);
|
* Windows needs at least 1 socket in select().
|
||||||
#else
|
*/
|
||||||
td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
|
td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
conn, 0, &td->thread_id);
|
if (td->dummy_sock == CURL_SOCKET_BAD)
|
||||||
|
goto err_exit;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CURLRES_IPV6
|
#ifdef HAVE_GETADDRINFO
|
||||||
DEBUGASSERT(hints);
|
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
|
||||||
td->hints = *hints;
|
|
||||||
#else
|
#else
|
||||||
(void) hints;
|
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!td->thread_hnd) {
|
if(!td->thread_hnd) {
|
||||||
#ifndef _WIN32_WCE
|
#ifndef _WIN32_WCE
|
||||||
SET_ERRNO(errno);
|
err = errno;
|
||||||
#endif
|
#endif
|
||||||
Curl_destroy_thread_data(&conn->async);
|
goto err_exit;
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
/* Waiting until the thread will initialize its data or it will exit due errors.
|
|
||||||
*/
|
|
||||||
thread_and_event[0] = td->thread_hnd;
|
|
||||||
thread_and_event[1] = td->event_thread_started;
|
|
||||||
if(WaitForMultipleObjects(sizeof(thread_and_event) /
|
|
||||||
sizeof(thread_and_event[0]),
|
|
||||||
(const HANDLE*)thread_and_event, FALSE,
|
|
||||||
INFINITE) == WAIT_FAILED) {
|
|
||||||
/* The resolver thread has been created,
|
|
||||||
* most probably it works now - ignoring this "minor" error
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
/* This socket is only to keep Curl_resolv_fdset() and select() happy;
|
|
||||||
* should never become signalled for read/write since it's unbound but
|
|
||||||
* Windows needs atleast 1 socket in select().
|
|
||||||
*/
|
|
||||||
td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
Curl_destroy_thread_data(&conn->async);
|
||||||
|
|
||||||
|
SET_ERRNO(err);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -521,85 +356,34 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
|||||||
{
|
{
|
||||||
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
|
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
long timeout;
|
CURLcode rc = CURLE_OK;
|
||||||
DWORD status;
|
|
||||||
CURLcode rc;
|
|
||||||
|
|
||||||
DEBUGASSERT(conn && td);
|
DEBUGASSERT(conn && td);
|
||||||
|
|
||||||
/* now, see if there's a connect timeout or a regular timeout to
|
|
||||||
use instead of the default one */
|
|
||||||
timeout =
|
|
||||||
conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
|
|
||||||
conn->data->set.timeout ? conn->data->set.timeout :
|
|
||||||
CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
|
|
||||||
|
|
||||||
/* wait for the thread to resolve the name */
|
/* wait for the thread to resolve the name */
|
||||||
status = WaitForSingleObject(td->event_resolved, timeout);
|
if (Curl_thread_join(&td->thread_hnd)) {
|
||||||
|
rc = getaddrinfo_complete(conn);
|
||||||
|
} else {
|
||||||
|
DEBUGASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* mark that we are now done waiting */
|
|
||||||
ReleaseMutex(td->mutex_waiting);
|
|
||||||
|
|
||||||
/* close our handle to the mutex, no point in hanging on to it */
|
|
||||||
CloseHandle(td->mutex_waiting);
|
|
||||||
td->mutex_waiting = NULL;
|
|
||||||
|
|
||||||
/* close the event handle, it's useless now */
|
|
||||||
CloseHandle(td->event_resolved);
|
|
||||||
td->event_resolved = NULL;
|
|
||||||
|
|
||||||
/* has the resolver thread succeeded in resolving our query ? */
|
|
||||||
if(status == WAIT_OBJECT_0) {
|
|
||||||
/* wait for the thread to exit, it's in the callback sequence */
|
|
||||||
if(WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
|
|
||||||
TerminateThread(td->thread_hnd, 0);
|
|
||||||
conn->async.done = TRUE;
|
conn->async.done = TRUE;
|
||||||
td->thread_status = (DWORD)-1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Thread finished before timeout; propagate Winsock error to this
|
|
||||||
* thread. 'conn->async.done = TRUE' is set in
|
|
||||||
* Curl_addrinfo4/6_callback().
|
|
||||||
*/
|
|
||||||
SET_SOCKERRNO(conn->async.status);
|
|
||||||
GetExitCodeThread(td->thread_hnd, &td->thread_status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
conn->async.done = TRUE;
|
|
||||||
td->thread_status = (DWORD)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entry)
|
if(entry)
|
||||||
*entry = conn->async.dns;
|
*entry = conn->async.dns;
|
||||||
|
|
||||||
rc = CURLE_OK;
|
|
||||||
|
|
||||||
if(!conn->async.dns) {
|
if(!conn->async.dns) {
|
||||||
/* a name was not resolved */
|
/* a name was not resolved */
|
||||||
if(td->thread_status == CURLE_OUT_OF_MEMORY) {
|
|
||||||
rc = CURLE_OUT_OF_MEMORY;
|
|
||||||
failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
|
|
||||||
}
|
|
||||||
else if(conn->async.done) {
|
|
||||||
if (conn->bits.httpproxy) {
|
if (conn->bits.httpproxy) {
|
||||||
failf(data, "Could not resolve proxy: %s; %s",
|
failf(data, "Could not resolve proxy: %s; %s",
|
||||||
conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
|
conn->async.hostname, Curl_strerror(conn, conn->async.status));
|
||||||
rc = CURLE_COULDNT_RESOLVE_PROXY;
|
rc = CURLE_COULDNT_RESOLVE_PROXY;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
failf(data, "Could not resolve host: %s; %s",
|
failf(data, "Could not resolve host: %s; %s",
|
||||||
conn->host.name, Curl_strerror(conn, conn->async.status));
|
conn->async.hostname, Curl_strerror(conn, conn->async.status));
|
||||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
|
|
||||||
failf(data, "Resolving host timed out: %s", conn->host.name);
|
|
||||||
rc = CURLE_OPERATION_TIMEDOUT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
rc = CURLE_OPERATION_TIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
Curl_destroy_thread_data(&conn->async);
|
Curl_destroy_thread_data(&conn->async);
|
||||||
|
|
||||||
@@ -618,19 +402,57 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
|
|||||||
struct Curl_dns_entry **entry)
|
struct Curl_dns_entry **entry)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
|
||||||
|
int done = 0;
|
||||||
|
|
||||||
*entry = NULL;
|
*entry = NULL;
|
||||||
|
|
||||||
if(conn->async.done) {
|
if (!td) {
|
||||||
/* we're done */
|
DEBUGASSERT(td);
|
||||||
|
return CURLE_COULDNT_RESOLVE_HOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
Curl_mutex_acquire(td->tsd.mtx);
|
||||||
|
done = td->tsd.done;
|
||||||
|
Curl_mutex_release(td->tsd.mtx);
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
getaddrinfo_complete(conn);
|
||||||
|
if (td->poll_interval != 0)
|
||||||
|
Curl_expire(conn->data, 0);
|
||||||
Curl_destroy_thread_data(&conn->async);
|
Curl_destroy_thread_data(&conn->async);
|
||||||
|
|
||||||
if(!conn->async.dns) {
|
if(!conn->async.dns) {
|
||||||
failf(data, "Could not resolve host: %s; %s",
|
failf(data, "Could not resolve host: %s; %s",
|
||||||
conn->host.name, Curl_strerror(conn, conn->async.status));
|
conn->host.name, Curl_strerror(conn, conn->async.status));
|
||||||
return CURLE_COULDNT_RESOLVE_HOST;
|
return CURLE_COULDNT_RESOLVE_HOST;
|
||||||
}
|
}
|
||||||
*entry = conn->async.dns;
|
*entry = conn->async.dns;
|
||||||
|
} else {
|
||||||
|
/* poll for name lookup done with exponential backoff up to 250ms */
|
||||||
|
int elapsed;
|
||||||
|
|
||||||
|
elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
|
||||||
|
if (elapsed < 0) {
|
||||||
|
elapsed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (td->poll_interval == 0) {
|
||||||
|
/* Start at 1ms poll interval */
|
||||||
|
td->poll_interval = 1;
|
||||||
|
} else if (elapsed >= td->interval_end) {
|
||||||
|
/* Back-off exponentially if last interval expired */
|
||||||
|
td->poll_interval *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (td->poll_interval > 250)
|
||||||
|
td->poll_interval = 250;
|
||||||
|
|
||||||
|
td->interval_end = elapsed + td->poll_interval;
|
||||||
|
|
||||||
|
Curl_expire(conn->data, td->poll_interval);
|
||||||
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,18 +465,18 @@ int Curl_resolv_getsock(struct connectdata *conn,
|
|||||||
|
|
||||||
if(td && td->dummy_sock != CURL_SOCKET_BAD) {
|
if(td && td->dummy_sock != CURL_SOCKET_BAD) {
|
||||||
if(numsocks) {
|
if(numsocks) {
|
||||||
/* return one socket waiting for writable, even though this is just
|
/* return one socket waiting for readable, even though this is just
|
||||||
a dummy */
|
a dummy */
|
||||||
socks[0] = td->dummy_sock;
|
socks[0] = td->dummy_sock;
|
||||||
return GETSOCK_WRITESOCK(0);
|
return GETSOCK_READSOCK(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CURLRES_IPV4
|
#if !defined(HAVE_GETADDRINFO)
|
||||||
/*
|
/*
|
||||||
* Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
|
* Curl_getaddrinfo() - for platforms without getaddrinfo
|
||||||
*/
|
*/
|
||||||
Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||||
const char *hostname,
|
const char *hostname,
|
||||||
@@ -665,7 +487,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
|
|
||||||
*waitp = 0; /* don't wait, we act synchronously */
|
*waitp = 0; /* default to synchronous response */
|
||||||
|
|
||||||
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
|
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
|
||||||
/* This is a dotted IP address 123.123.123.123-style */
|
/* This is a dotted IP address 123.123.123.123-style */
|
||||||
@@ -673,27 +495,18 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
|
|
||||||
/* fire up a new resolver thread! */
|
/* fire up a new resolver thread! */
|
||||||
if(init_resolve_thread(conn, hostname, port, NULL)) {
|
if(init_resolve_thread(conn, hostname, port, NULL)) {
|
||||||
*waitp = TRUE; /* please wait for the response */
|
*waitp = 1; /* expect asynchronous response */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fall-back to blocking version */
|
/* fall-back to blocking version */
|
||||||
infof(data, "init_resolve_thread() failed for %s; %s\n",
|
return Curl_ipv4_resolve_r(hostname, port);
|
||||||
hostname, Curl_strerror(conn, ERRNO));
|
|
||||||
|
|
||||||
h = gethostbyname(hostname);
|
|
||||||
if(!h) {
|
|
||||||
infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
|
|
||||||
hostname, port, Curl_strerror(conn, SOCKERRNO));
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
return Curl_he2ai(h, port);
|
|
||||||
}
|
|
||||||
#endif /* CURLRES_IPV4 */
|
|
||||||
|
|
||||||
#ifdef CURLRES_IPV6
|
#else /* HAVE_GETADDRINFO */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_getaddrinfo() - for Windows threading IPv6 enabled
|
* Curl_getaddrinfo() - for getaddrinfo
|
||||||
*/
|
*/
|
||||||
Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||||
const char *hostname,
|
const char *hostname,
|
||||||
@@ -704,11 +517,12 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
Curl_addrinfo *res;
|
Curl_addrinfo *res;
|
||||||
int error;
|
int error;
|
||||||
char sbuf[NI_MAXSERV];
|
char sbuf[NI_MAXSERV];
|
||||||
int pf;
|
int pf = PF_INET;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
*waitp = FALSE; /* default to synch response */
|
*waitp = 0; /* default to synchronous response */
|
||||||
|
|
||||||
|
#if !defined(CURLRES_IPV4)
|
||||||
/*
|
/*
|
||||||
* Check if a limited name resolve has been requested.
|
* Check if a limited name resolve has been requested.
|
||||||
*/
|
*/
|
||||||
@@ -741,6 +555,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
sclose(s);
|
sclose(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* !CURLRES_IPV4 */
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_family = pf;
|
hints.ai_family = pf;
|
||||||
@@ -748,11 +563,11 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
#if 0 /* removed nov 8 2005 before 7.15.1 */
|
#if 0 /* removed nov 8 2005 before 7.15.1 */
|
||||||
hints.ai_flags = AI_CANONNAME;
|
hints.ai_flags = AI_CANONNAME;
|
||||||
#endif
|
#endif
|
||||||
itoa(port, sbuf, 10);
|
snprintf(sbuf, sizeof(sbuf), "%d", port);
|
||||||
|
|
||||||
/* fire up a new resolver thread! */
|
/* fire up a new resolver thread! */
|
||||||
if(init_resolve_thread(conn, hostname, port, &hints)) {
|
if(init_resolve_thread(conn, hostname, port, &hints)) {
|
||||||
*waitp = TRUE; /* please wait for the response */
|
*waitp = 1; /* expect asynchronous response */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,5 +583,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#endif /* CURLRES_IPV6 */
|
|
||||||
|
#endif /* HAVE_GETADDRINFO */
|
||||||
|
|
||||||
#endif /* CURLRES_THREADED */
|
#endif /* CURLRES_THREADED */
|
||||||
|
|||||||
1151
lib/http.c
1151
lib/http.c
File diff suppressed because it is too large
Load Diff
76
lib/http.h
76
lib/http.h
@@ -8,7 +8,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -35,8 +35,40 @@ bool Curl_compareheader(const char *headerline, /* line to check */
|
|||||||
const char *header, /* header keyword _with_ colon */
|
const char *header, /* header keyword _with_ colon */
|
||||||
const char *content); /* content string to find */
|
const char *content); /* content string to find */
|
||||||
|
|
||||||
|
char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader);
|
||||||
|
|
||||||
char *Curl_copy_header_value(const char *h);
|
char *Curl_copy_header_value(const char *h);
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* The add_buffer series of functions are used to build one large memory chunk
|
||||||
|
* from repeated function invokes. Used so that the entire HTTP request can
|
||||||
|
* be sent in one go.
|
||||||
|
*/
|
||||||
|
struct Curl_send_buffer {
|
||||||
|
char *buffer;
|
||||||
|
size_t size_max;
|
||||||
|
size_t size_used;
|
||||||
|
};
|
||||||
|
typedef struct Curl_send_buffer Curl_send_buffer;
|
||||||
|
|
||||||
|
Curl_send_buffer *Curl_add_buffer_init(void);
|
||||||
|
CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
|
||||||
|
CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
|
||||||
|
CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
||||||
|
struct connectdata *conn,
|
||||||
|
long *bytes_written,
|
||||||
|
size_t included_body_bytes,
|
||||||
|
int socketindex);
|
||||||
|
|
||||||
|
|
||||||
|
CURLcode Curl_add_timecondition(struct SessionHandle *data,
|
||||||
|
Curl_send_buffer *buf);
|
||||||
|
CURLcode Curl_add_custom_headers(struct connectdata *conn,
|
||||||
|
Curl_send_buffer *req_buffer);
|
||||||
|
|
||||||
|
|
||||||
/* ftp can use this as well */
|
/* ftp can use this as well */
|
||||||
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||||
int tunnelsocket,
|
int tunnelsocket,
|
||||||
@@ -87,5 +119,45 @@ int Curl_http_should_fail(struct connectdata *conn);
|
|||||||
#define TINY_INITIAL_POST_SIZE 1024
|
#define TINY_INITIAL_POST_SIZE 1024
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif /* CURL_DISABLE_HTTP */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* HTTP unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
struct HTTP {
|
||||||
|
struct FormData *sendit;
|
||||||
|
curl_off_t postsize; /* off_t to handle large file sizes */
|
||||||
|
const char *postdata;
|
||||||
|
|
||||||
|
const char *p_pragma; /* Pragma: string */
|
||||||
|
const char *p_accept; /* Accept: string */
|
||||||
|
curl_off_t readbytecount;
|
||||||
|
curl_off_t writebytecount;
|
||||||
|
|
||||||
|
/* For FORM posting */
|
||||||
|
struct Form form;
|
||||||
|
|
||||||
|
struct back {
|
||||||
|
curl_read_callback fread_func; /* backup storage for fread pointer */
|
||||||
|
void *fread_in; /* backup storage for fread_in pointer */
|
||||||
|
const char *postdata;
|
||||||
|
curl_off_t postsize;
|
||||||
|
} backup;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HTTPSEND_NADA, /* init */
|
||||||
|
HTTPSEND_REQUEST, /* sending a request */
|
||||||
|
HTTPSEND_BODY, /* sending body */
|
||||||
|
HTTPSEND_LAST /* never use this */
|
||||||
|
} sending;
|
||||||
|
|
||||||
|
void *send_buffer; /* used if the request couldn't be sent in one chunk,
|
||||||
|
points to an allocated send_buffer struct */
|
||||||
|
};
|
||||||
|
|
||||||
|
CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
|
||||||
|
struct connectdata *conn,
|
||||||
|
ssize_t *nread,
|
||||||
|
bool *stop_reading);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ static void lm_resp(const unsigned char *keys,
|
|||||||
setup_des_key(keys+14, DESKEY(ks));
|
setup_des_key(keys+14, DESKEY(ks));
|
||||||
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
|
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
|
||||||
DESKEY(ks), DES_ENCRYPT);
|
DESKEY(ks), DES_ENCRYPT);
|
||||||
#elif USE_GNUTLS
|
#elif defined(USE_GNUTLS)
|
||||||
gcry_cipher_hd_t des;
|
gcry_cipher_hd_t des;
|
||||||
|
|
||||||
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
||||||
@@ -447,7 +447,7 @@ static void mk_lm_hash(struct SessionHandle *data,
|
|||||||
setup_des_key(pw+7, DESKEY(ks));
|
setup_des_key(pw+7, DESKEY(ks));
|
||||||
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
|
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
|
||||||
DESKEY(ks), DES_ENCRYPT);
|
DESKEY(ks), DES_ENCRYPT);
|
||||||
#elif USE_GNUTLS
|
#elif defined(USE_GNUTLS)
|
||||||
gcry_cipher_hd_t des;
|
gcry_cipher_hd_t des;
|
||||||
|
|
||||||
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
||||||
@@ -508,7 +508,7 @@ static CURLcode mk_nt_hash(struct SessionHandle *data,
|
|||||||
MD4_Init(&MD4pw);
|
MD4_Init(&MD4pw);
|
||||||
MD4_Update(&MD4pw, pw, 2*len);
|
MD4_Update(&MD4pw, pw, 2*len);
|
||||||
MD4_Final(ntbuffer, &MD4pw);
|
MD4_Final(ntbuffer, &MD4pw);
|
||||||
#elif USE_GNUTLS
|
#elif defined(USE_GNUTLS)
|
||||||
gcry_md_hd_t MD4pw;
|
gcry_md_hd_t MD4pw;
|
||||||
gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
|
gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
|
||||||
gcry_md_write(MD4pw, pw, 2*len);
|
gcry_md_write(MD4pw, pw, 2*len);
|
||||||
@@ -911,7 +911,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
|||||||
MD5_CTX MD5pw;
|
MD5_CTX MD5pw;
|
||||||
Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
|
Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
|
||||||
RAND_bytes(entropy,8);
|
RAND_bytes(entropy,8);
|
||||||
#elif USE_GNUTLS
|
#elif defined(USE_GNUTLS)
|
||||||
gcry_md_hd_t MD5pw;
|
gcry_md_hd_t MD5pw;
|
||||||
Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
|
Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
|
||||||
gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
|
gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
|
||||||
@@ -930,7 +930,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
|||||||
MD5_Init(&MD5pw);
|
MD5_Init(&MD5pw);
|
||||||
MD5_Update(&MD5pw, tmp, 16);
|
MD5_Update(&MD5pw, tmp, 16);
|
||||||
MD5_Final(md5sum, &MD5pw);
|
MD5_Final(md5sum, &MD5pw);
|
||||||
#elif USE_GNUTLS
|
#elif defined(USE_GNUTLS)
|
||||||
gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
|
gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
|
||||||
gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
|
gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
|
||||||
memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
|
memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
#ifdef HAVE_STROPTS_H
|
#ifdef HAVE_STROPTS_H
|
||||||
# include <stropts.h>
|
# include <stropts.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
# include <inet.h>
|
# include <inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
1028
lib/imap.c
Normal file
1028
lib/imap.c
Normal file
File diff suppressed because it is too large
Load Diff
56
lib/imap.h
Normal file
56
lib/imap.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef __IMAP_H
|
||||||
|
#define __IMAP_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, 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 "pingpong.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* IMAP unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
typedef enum {
|
||||||
|
IMAP_STOP, /* do nothing state, stops the state machine */
|
||||||
|
IMAP_SERVERGREET, /* waiting for the initial greeting immediately after
|
||||||
|
a connect */
|
||||||
|
IMAP_LOGIN,
|
||||||
|
IMAP_STARTTLS,
|
||||||
|
IMAP_SELECT,
|
||||||
|
IMAP_FETCH,
|
||||||
|
IMAP_LOGOUT,
|
||||||
|
IMAP_LAST /* never used */
|
||||||
|
} imapstate;
|
||||||
|
|
||||||
|
/* imap_conn is used for struct connection-oriented data in the connectdata
|
||||||
|
struct */
|
||||||
|
struct imap_conn {
|
||||||
|
struct pingpong pp;
|
||||||
|
char *mailbox; /* what to FETCH */
|
||||||
|
imapstate state; /* always use imap.c:state() to change state! */
|
||||||
|
int cmdid; /* id number/index */
|
||||||
|
const char *idstr; /* pointer to a string for which to wait for as id */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct Curl_handler Curl_handler_imap;
|
||||||
|
extern const struct Curl_handler Curl_handler_imaps;
|
||||||
|
|
||||||
|
#endif /* __IMAP_H */
|
||||||
20
lib/ldap.c
20
lib/ldap.c
@@ -200,7 +200,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get the URL scheme ( either ldap or ldaps ) */
|
/* Get the URL scheme ( either ldap or ldaps ) */
|
||||||
if(Curl_raw_equal(conn->protostr, "LDAPS"))
|
if(conn->protocol & PROT_SSL)
|
||||||
ldap_ssl = 1;
|
ldap_ssl = 1;
|
||||||
infof(data, "LDAP local: trying to establish %s connection\n",
|
infof(data, "LDAP local: trying to establish %s connection\n",
|
||||||
ldap_ssl ? "encrypted" : "cleartext");
|
ldap_ssl ? "encrypted" : "cleartext");
|
||||||
@@ -262,7 +262,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
server = ldapssl_init(conn->host.name, (int)conn->port, 1);
|
server = ldapssl_init(conn->host.name, (int)conn->port, 1);
|
||||||
if(server == NULL) {
|
if(server == NULL) {
|
||||||
failf(data, "LDAP local: Cannot connect to %s:%d",
|
failf(data, "LDAP local: Cannot connect to %s:%hu",
|
||||||
conn->host.name, conn->port);
|
conn->host.name, conn->port);
|
||||||
status = CURLE_COULDNT_CONNECT;
|
status = CURLE_COULDNT_CONNECT;
|
||||||
goto quit;
|
goto quit;
|
||||||
@@ -302,7 +302,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
server = ldap_init(conn->host.name, (int)conn->port);
|
server = ldap_init(conn->host.name, (int)conn->port);
|
||||||
if(server == NULL) {
|
if(server == NULL) {
|
||||||
failf(data, "LDAP local: Cannot connect to %s:%d",
|
failf(data, "LDAP local: Cannot connect to %s:%hu",
|
||||||
conn->host.name, conn->port);
|
conn->host.name, conn->port);
|
||||||
status = CURLE_COULDNT_CONNECT;
|
status = CURLE_COULDNT_CONNECT;
|
||||||
goto quit;
|
goto quit;
|
||||||
@@ -337,7 +337,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
|
|||||||
} else {
|
} else {
|
||||||
server = ldap_init(conn->host.name, (int)conn->port);
|
server = ldap_init(conn->host.name, (int)conn->port);
|
||||||
if(server == NULL) {
|
if(server == NULL) {
|
||||||
failf(data, "LDAP local: Cannot connect to %s:%d",
|
failf(data, "LDAP local: Cannot connect to %s:%hu",
|
||||||
conn->host.name, conn->port);
|
conn->host.name, conn->port);
|
||||||
status = CURLE_COULDNT_CONNECT;
|
status = CURLE_COULDNT_CONNECT;
|
||||||
goto quit;
|
goto quit;
|
||||||
@@ -488,15 +488,15 @@ static void _ldap_trace (const char *fmt, ...)
|
|||||||
*/
|
*/
|
||||||
static int str2scope (const char *p)
|
static int str2scope (const char *p)
|
||||||
{
|
{
|
||||||
if(!stricmp(p, "one"))
|
if(strequal(p, "one"))
|
||||||
return LDAP_SCOPE_ONELEVEL;
|
return LDAP_SCOPE_ONELEVEL;
|
||||||
if(!stricmp(p, "onetree"))
|
if(strequal(p, "onetree"))
|
||||||
return LDAP_SCOPE_ONELEVEL;
|
return LDAP_SCOPE_ONELEVEL;
|
||||||
if(!stricmp(p, "base"))
|
if(strequal(p, "base"))
|
||||||
return LDAP_SCOPE_BASE;
|
return LDAP_SCOPE_BASE;
|
||||||
if(!stricmp(p, "sub"))
|
if(strequal(p, "sub"))
|
||||||
return LDAP_SCOPE_SUBTREE;
|
return LDAP_SCOPE_SUBTREE;
|
||||||
if(!stricmp( p, "subtree"))
|
if(strequal( p, "subtree"))
|
||||||
return LDAP_SCOPE_SUBTREE;
|
return LDAP_SCOPE_SUBTREE;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@@ -582,7 +582,7 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
|
|||||||
if(!conn->data ||
|
if(!conn->data ||
|
||||||
!conn->data->state.path ||
|
!conn->data->state.path ||
|
||||||
conn->data->state.path[0] != '/' ||
|
conn->data->state.path[0] != '/' ||
|
||||||
!checkprefix(conn->protostr, conn->data->change.url))
|
!checkprefix("LDAP", conn->data->change.url))
|
||||||
return LDAP_INVALID_SYNTAX;
|
return LDAP_INVALID_SYNTAX;
|
||||||
|
|
||||||
ludp->lud_scope = LDAP_SCOPE_BASE;
|
ludp->lud_scope = LDAP_SCOPE_BASE;
|
||||||
|
|||||||
@@ -10,17 +10,19 @@ ATCPSDKI= /GG/netinclude
|
|||||||
CC = m68k-amigaos-gcc
|
CC = m68k-amigaos-gcc
|
||||||
CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall
|
CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall
|
||||||
|
|
||||||
OBJS = amigaos.c base64.c connect.c content_encoding.c cookie.c dict.c easy.c \
|
OBJS = amigaos.c \
|
||||||
escape.c file.c formdata.c ftp.c getenv.c getinfo.c hash.c hostip.c \
|
file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||||
hostip4.c hostsyn.c http.c http_chunks.c http_digest.c \
|
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
|
||||||
http_negotiate.c http_ntlm.c if2ip.c inet_ntop.c inet_pton.c krb4.c \
|
ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \
|
||||||
ldap.c llist.c md5.c memdebug.c mprintf.c multi.c netrc.c parsedate.c \
|
netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \
|
||||||
progress.c security.c select.c sendf.c share.c speedcheck.c ssluse.c \
|
krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c \
|
||||||
strequal.c strtok.c telnet.c timeval.c transfer.c url.c version.c \
|
multi.c content_encoding.c share.c http_digest.c md5.c curl_rand.c \
|
||||||
sslgen.c gtls.c strerror.c rawstr.c curl_addrinfo.c curl_rand.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 tftp.c splay.c \
|
||||||
|
strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \
|
||||||
socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \
|
socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \
|
||||||
curl_memrchr.c
|
curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c
|
||||||
|
|
||||||
|
|
||||||
all: $(OBJS:.c=.o)
|
all: $(OBJS:.c=.o)
|
||||||
ar cru libcurl.a $(OBJS:.c=.o)
|
ar cru libcurl.a $(OBJS:.c=.o)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -104,12 +105,14 @@ static bool countcheck(const char *func, int line, const char *source)
|
|||||||
should not be made */
|
should not be made */
|
||||||
if(memlimit && source) {
|
if(memlimit && source) {
|
||||||
if(!memsize) {
|
if(!memsize) {
|
||||||
if(logfile && source)
|
if(source) {
|
||||||
fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
|
/* log to file */
|
||||||
|
curl_memlog("LIMIT %s:%d %s reached memlimit\n",
|
||||||
source, line, func);
|
source, line, func);
|
||||||
if(source)
|
/* log to stderr also */
|
||||||
fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
|
fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
|
||||||
source, line, func);
|
source, line, func);
|
||||||
|
}
|
||||||
SET_ERRNO(ENOMEM);
|
SET_ERRNO(ENOMEM);
|
||||||
return TRUE; /* RETURN ERROR! */
|
return TRUE; /* RETURN ERROR! */
|
||||||
}
|
}
|
||||||
@@ -117,8 +120,8 @@ static bool countcheck(const char *func, int line, const char *source)
|
|||||||
memsize--; /* countdown */
|
memsize--; /* countdown */
|
||||||
|
|
||||||
/* log the countdown */
|
/* log the countdown */
|
||||||
if(logfile && source)
|
if(source)
|
||||||
fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
|
curl_memlog("LIMIT %s:%d %ld ALLOCS left\n",
|
||||||
source, line, memsize);
|
source, line, memsize);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -146,8 +149,8 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
|
|||||||
mem->size = wantedsize;
|
mem->size = wantedsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(logfile && source)
|
if(source)
|
||||||
fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n",
|
curl_memlog("MEM %s:%d malloc(%zd) = %p\n",
|
||||||
source, line, wantedsize, mem ? mem->mem : 0);
|
source, line, wantedsize, mem ? mem->mem : 0);
|
||||||
return (mem ? mem->mem : NULL);
|
return (mem ? mem->mem : NULL);
|
||||||
}
|
}
|
||||||
@@ -175,8 +178,8 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
|
|||||||
mem->size = user_size;
|
mem->size = user_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(logfile && source)
|
if(source)
|
||||||
fprintf(logfile, "MEM %s:%d calloc(%zu,%zu) = %p\n",
|
curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
|
||||||
source, line, wanted_elements, wanted_size, mem?mem->mem:0);
|
source, line, wanted_elements, wanted_size, mem?mem->mem:0);
|
||||||
return (mem ? mem->mem : NULL);
|
return (mem ? mem->mem : NULL);
|
||||||
}
|
}
|
||||||
@@ -197,8 +200,8 @@ char *curl_dostrdup(const char *str, int line, const char *source)
|
|||||||
if(mem)
|
if(mem)
|
||||||
memcpy(mem, str, len);
|
memcpy(mem, str, len);
|
||||||
|
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "MEM %s:%d strdup(%p) (%zu) = %p\n",
|
curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
|
||||||
source, line, str, len, mem);
|
source, line, str, len, mem);
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
@@ -222,8 +225,8 @@ void *curl_dorealloc(void *ptr, size_t wantedsize,
|
|||||||
mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
|
mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
|
||||||
|
|
||||||
mem = (Curl_crealloc)(mem, size);
|
mem = (Curl_crealloc)(mem, size);
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "MEM %s:%d realloc(%p, %zu) = %p\n",
|
curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
|
||||||
source, line, ptr, wantedsize, mem?mem->mem:NULL);
|
source, line, ptr, wantedsize, mem?mem->mem:NULL);
|
||||||
|
|
||||||
if(mem) {
|
if(mem) {
|
||||||
@@ -248,16 +251,16 @@ void curl_dofree(void *ptr, int line, const char *source)
|
|||||||
/* free for real */
|
/* free for real */
|
||||||
(Curl_cfree)(mem);
|
(Curl_cfree)(mem);
|
||||||
|
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
|
curl_memlog("MEM %s:%d free(%p)\n", source, line, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int curl_socket(int domain, int type, int protocol, int line,
|
int curl_socket(int domain, int type, int protocol, int line,
|
||||||
const char *source)
|
const char *source)
|
||||||
{
|
{
|
||||||
int sockfd=socket(domain, type, protocol);
|
int sockfd=socket(domain, type, protocol);
|
||||||
if(logfile && (sockfd!=-1))
|
if(source && (sockfd!=-1))
|
||||||
fprintf(logfile, "FD %s:%d socket() = %d\n",
|
curl_memlog("FD %s:%d socket() = %d\n",
|
||||||
source, line, sockfd);
|
source, line, sockfd);
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
@@ -268,8 +271,8 @@ int curl_accept(int s, void *saddr, void *saddrlen,
|
|||||||
struct sockaddr *addr = (struct sockaddr *)saddr;
|
struct sockaddr *addr = (struct sockaddr *)saddr;
|
||||||
curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
|
curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
|
||||||
int sockfd=accept(s, addr, addrlen);
|
int sockfd=accept(s, addr, addrlen);
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "FD %s:%d accept() = %d\n",
|
curl_memlog("FD %s:%d accept() = %d\n",
|
||||||
source, line, sockfd);
|
source, line, sockfd);
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
@@ -277,8 +280,8 @@ int curl_accept(int s, void *saddr, void *saddrlen,
|
|||||||
/* separate function to allow libcurl to mark a "faked" close */
|
/* separate function to allow libcurl to mark a "faked" close */
|
||||||
void curl_mark_sclose(int sockfd, int line, const char *source)
|
void curl_mark_sclose(int sockfd, int line, const char *source)
|
||||||
{
|
{
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "FD %s:%d sclose(%d)\n",
|
curl_memlog("FD %s:%d sclose(%d)\n",
|
||||||
source, line, sockfd);
|
source, line, sockfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,8 +297,8 @@ FILE *curl_fopen(const char *file, const char *mode,
|
|||||||
int line, const char *source)
|
int line, const char *source)
|
||||||
{
|
{
|
||||||
FILE *res=fopen(file, mode);
|
FILE *res=fopen(file, mode);
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
|
curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
|
||||||
source, line, file, mode, res);
|
source, line, file, mode, res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -305,8 +308,8 @@ FILE *curl_fdopen(int filedes, const char *mode,
|
|||||||
int line, const char *source)
|
int line, const char *source)
|
||||||
{
|
{
|
||||||
FILE *res=fdopen(filedes, mode);
|
FILE *res=fdopen(filedes, mode);
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
|
curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
|
||||||
source, line, filedes, mode, res);
|
source, line, filedes, mode, res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -319,9 +322,39 @@ int curl_fclose(FILE *file, int line, const char *source)
|
|||||||
assert(file != NULL);
|
assert(file != NULL);
|
||||||
|
|
||||||
res=fclose(file);
|
res=fclose(file);
|
||||||
if(logfile)
|
if(source)
|
||||||
fprintf(logfile, "FILE %s:%d fclose(%p)\n",
|
curl_memlog("FILE %s:%d fclose(%p)\n",
|
||||||
source, line, file);
|
source, line, file);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LOGLINE_BUFSIZE 1024
|
||||||
|
|
||||||
|
/* this does the writting to the memory tracking log file */
|
||||||
|
void curl_memlog(const char *format, ...)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int nchars;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if(!logfile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
|
||||||
|
if(!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if(nchars > LOGLINE_BUFSIZE - 1)
|
||||||
|
nchars = LOGLINE_BUFSIZE - 1;
|
||||||
|
|
||||||
|
if(nchars > 0)
|
||||||
|
fwrite(buf, 1, nchars, logfile);
|
||||||
|
|
||||||
|
(Curl_cfree)(buf);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CURLDEBUG */
|
#endif /* CURLDEBUG */
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -54,6 +54,7 @@ CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
|
|||||||
CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
|
CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
|
||||||
CURL_EXTERN void curl_memdebug(const char *logname);
|
CURL_EXTERN void curl_memdebug(const char *logname);
|
||||||
CURL_EXTERN void curl_memlimit(long limit);
|
CURL_EXTERN void curl_memlimit(long limit);
|
||||||
|
CURL_EXTERN void curl_memlog(const char *format, ...);
|
||||||
|
|
||||||
/* file descriptor manipulators */
|
/* file descriptor manipulators */
|
||||||
CURL_EXTERN int curl_socket(int domain, int type, int protocol, int line , const char *);
|
CURL_EXTERN int curl_socket(int domain, int type, int protocol, int line , const char *);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1999 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1999 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -1219,7 +1219,7 @@ int main()
|
|||||||
|
|
||||||
curl_mprintf("%3d %5d\n", 10, 1998);
|
curl_mprintf("%3d %5d\n", 10, 1998);
|
||||||
|
|
||||||
ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
|
ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a kiss in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
|
||||||
|
|
||||||
puts(ptr);
|
puts(ptr);
|
||||||
|
|
||||||
|
|||||||
79
lib/multi.c
79
lib/multi.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -181,7 +181,7 @@ struct Curl_multi {
|
|||||||
previous callback */
|
previous callback */
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool multi_conn_using(struct Curl_multi *multi,
|
static struct connectdata *conn_using(struct Curl_multi *multi,
|
||||||
struct SessionHandle *data);
|
struct SessionHandle *data);
|
||||||
static void singlesocket(struct Curl_multi *multi,
|
static void singlesocket(struct Curl_multi *multi,
|
||||||
struct Curl_one_easy *easy);
|
struct Curl_one_easy *easy);
|
||||||
@@ -258,7 +258,6 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
|||||||
struct Curl_sh_entry {
|
struct Curl_sh_entry {
|
||||||
struct SessionHandle *easy;
|
struct SessionHandle *easy;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
long inuse;
|
|
||||||
int action; /* what action READ/WRITE this socket waits for */
|
int action; /* what action READ/WRITE this socket waits for */
|
||||||
curl_socket_t socket; /* mainly to ease debugging */
|
curl_socket_t socket; /* mainly to ease debugging */
|
||||||
void *socketp; /* settable by users with curl_multi_assign() */
|
void *socketp; /* settable by users with curl_multi_assign() */
|
||||||
@@ -568,7 +567,7 @@ static void debug_print_sock_hash(void *p)
|
|||||||
struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
|
struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
|
||||||
|
|
||||||
fprintf(stderr, " [easy %p/magic %x/socket %d]",
|
fprintf(stderr, " [easy %p/magic %x/socket %d]",
|
||||||
(void *)sh->easy, sh->easy->magic, sh->socket);
|
(void *)sh->easy, sh->easy->magic, (int)sh->socket);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -577,6 +576,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
{
|
{
|
||||||
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||||
struct Curl_one_easy *easy;
|
struct Curl_one_easy *easy;
|
||||||
|
struct connectdata *conn;
|
||||||
|
|
||||||
/* First, make some basic checks that the CURLM handle is a good handle */
|
/* First, make some basic checks that the CURLM handle is a good handle */
|
||||||
if(!GOOD_MULTI_HANDLE(multi))
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
@@ -649,6 +649,9 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn);
|
Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* figure out if the easy handle is used by a connection in the cache */
|
||||||
|
conn = conn_using(multi, easy->easy_handle);
|
||||||
|
|
||||||
/* If this easy_handle was the last one in charge for one or more
|
/* If this easy_handle was the last one in charge for one or more
|
||||||
connections in the shared connection cache, we might need to keep this
|
connections in the shared connection cache, we might need to keep this
|
||||||
handle around until either A) the connection is closed and killed
|
handle around until either A) the connection is closed and killed
|
||||||
@@ -665,17 +668,23 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
we need to add this handle to the list of "easy handles kept around for
|
we need to add this handle to the list of "easy handles kept around for
|
||||||
nice connection closures".
|
nice connection closures".
|
||||||
*/
|
*/
|
||||||
if(multi_conn_using(multi, easy->easy_handle)) {
|
if(conn) {
|
||||||
/* There's at least one connection using this handle so we must keep
|
if(conn->protocol & PROT_CLOSEACTION) {
|
||||||
this handle around. We also keep the connection cache pointer
|
/* There's at least one CLOSEACTION connection using this handle so we
|
||||||
pointing to the shared one since that will be used on close as
|
must keep this handle around. We also keep the connection cache
|
||||||
well. */
|
pointer pointing to the shared one since that will be used on close
|
||||||
|
as well. */
|
||||||
easy->easy_handle->state.shared_conn = multi;
|
easy->easy_handle->state.shared_conn = multi;
|
||||||
|
|
||||||
/* this handle is still being used by a shared connection cache and
|
/* this handle is still being used by a shared connection cache and
|
||||||
thus we leave it around for now */
|
thus we leave it around for now */
|
||||||
add_closure(multi, easy->easy_handle);
|
add_closure(multi, easy->easy_handle);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
/* disconect the easy handle from the connection since the connection
|
||||||
|
will now remain but this easy handle is going */
|
||||||
|
conn->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) {
|
if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) {
|
||||||
/* if this was using the shared connection cache we clear the pointer
|
/* if this was using the shared connection cache we clear the pointer
|
||||||
@@ -914,7 +923,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
/* Handle the case when the pipe breaks, i.e., the connection
|
/* Handle the case when the pipe breaks, i.e., the connection
|
||||||
we're using gets cleaned up and we're left with nothing. */
|
we're using gets cleaned up and we're left with nothing. */
|
||||||
if(easy->easy_handle->state.pipe_broke) {
|
if(easy->easy_handle->state.pipe_broke) {
|
||||||
infof(easy->easy_handle, "Pipe broke: handle 0x%x, url = %s\n",
|
infof(easy->easy_handle, "Pipe broke: handle 0x%p, url = %s\n",
|
||||||
easy, easy->easy_handle->state.path);
|
easy, easy->easy_handle->state.path);
|
||||||
|
|
||||||
if(easy->state != CURLM_STATE_COMPLETED) {
|
if(easy->state != CURLM_STATE_COMPLETED) {
|
||||||
@@ -1090,15 +1099,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
multistate(easy, CURLM_STATE_PROTOCONNECT);
|
multistate(easy, CURLM_STATE_PROTOCONNECT);
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
/* after the connect has completed, go WAITDO or DO */
|
/* after the connect has completed, go WAITDO or DO */
|
||||||
multistate(easy, multi->pipelining_enabled?
|
multistate(easy, multi->pipelining_enabled?
|
||||||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
|
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_PROTOCONNECT:
|
case CURLM_STATE_PROTOCONNECT:
|
||||||
@@ -1122,12 +1131,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
case CURLM_STATE_WAITDO:
|
case CURLM_STATE_WAITDO:
|
||||||
/* Wait for our turn to DO when we're pipelining requests */
|
/* Wait for our turn to DO when we're pipelining requests */
|
||||||
#ifdef DEBUGBUILD
|
#ifdef DEBUGBUILD
|
||||||
infof(easy->easy_handle, "Conn %d send pipe %d inuse %d athead %d\n",
|
infof(easy->easy_handle, "Conn %ld send pipe %zu inuse %d athead %d\n",
|
||||||
easy->easy_conn->connectindex,
|
easy->easy_conn->connectindex,
|
||||||
easy->easy_conn->send_pipe->size,
|
easy->easy_conn->send_pipe->size,
|
||||||
easy->easy_conn->writechannel_inuse,
|
easy->easy_conn->writechannel_inuse?1:0,
|
||||||
isHandleAtHead(easy->easy_handle,
|
isHandleAtHead(easy->easy_handle,
|
||||||
easy->easy_conn->send_pipe));
|
easy->easy_conn->send_pipe)?1:0);
|
||||||
#endif
|
#endif
|
||||||
if(!easy->easy_conn->writechannel_inuse &&
|
if(!easy->easy_conn->writechannel_inuse &&
|
||||||
isHandleAtHead(easy->easy_handle,
|
isHandleAtHead(easy->easy_handle,
|
||||||
@@ -1192,7 +1201,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
disconnect_conn = TRUE;
|
disconnect_conn = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
retry = newurl?TRUE:FALSE;
|
retry = (bool)(newurl?TRUE:FALSE);
|
||||||
|
|
||||||
Curl_posttransfer(easy->easy_handle);
|
Curl_posttransfer(easy->easy_handle);
|
||||||
drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
|
drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
|
||||||
@@ -1310,12 +1319,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
}
|
}
|
||||||
#ifdef DEBUGBUILD
|
#ifdef DEBUGBUILD
|
||||||
else {
|
else {
|
||||||
infof(easy->easy_handle, "Conn %d recv pipe %d inuse %d athead %d\n",
|
infof(easy->easy_handle, "Conn %ld recv pipe %zu inuse %d athead %d\n",
|
||||||
easy->easy_conn->connectindex,
|
easy->easy_conn->connectindex,
|
||||||
easy->easy_conn->recv_pipe->size,
|
easy->easy_conn->recv_pipe->size,
|
||||||
easy->easy_conn->readchannel_inuse,
|
easy->easy_conn->readchannel_inuse?1:0,
|
||||||
isHandleAtHead(easy->easy_handle,
|
isHandleAtHead(easy->easy_handle,
|
||||||
easy->easy_conn->recv_pipe));
|
easy->easy_conn->recv_pipe)?1:0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@@ -1384,7 +1393,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
|
|
||||||
easy->result = Curl_retry_request(easy->easy_conn, &newurl);
|
easy->result = Curl_retry_request(easy->easy_conn, &newurl);
|
||||||
if(!easy->result)
|
if(!easy->result)
|
||||||
retry = newurl?TRUE:FALSE;
|
retry = (bool)(newurl?TRUE:FALSE);
|
||||||
|
|
||||||
/* call this even if the readwrite function returned error */
|
/* call this even if the readwrite function returned error */
|
||||||
Curl_posttransfer(easy->easy_handle);
|
Curl_posttransfer(easy->easy_handle);
|
||||||
@@ -1559,17 +1568,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
multi->num_msgs++; /* increase message counter */
|
multi->num_msgs++; /* increase message counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CURLM_CALL_MULTI_PERFORM == result)
|
|
||||||
/* Set the timeout for this handle to expire really soon so that it will
|
|
||||||
be taken care of even when this handle is added in the midst of
|
|
||||||
operation when only the curl_multi_socket() API is used. During that
|
|
||||||
flow, only sockets that time-out or have actions will be dealt
|
|
||||||
with. Since this handle has no action yet, we make sure it times out to
|
|
||||||
get things to happen. Also, this makes it less important for callers of
|
|
||||||
the curl_multi_* functions to bother about the CURLM_CALL_MULTI_PERFORM
|
|
||||||
return code, as long as they deal with the timeouts properly. */
|
|
||||||
Curl_expire(easy->easy_handle, 1);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1588,7 +1586,10 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
while(easy != &multi->easy) {
|
while(easy != &multi->easy) {
|
||||||
CURLMcode result;
|
CURLMcode result;
|
||||||
|
|
||||||
|
do
|
||||||
result = multi_runsingle(multi, easy);
|
result = multi_runsingle(multi, easy);
|
||||||
|
while (CURLM_CALL_MULTI_PERFORM == result);
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
returncode = result;
|
returncode = result;
|
||||||
|
|
||||||
@@ -1750,7 +1751,6 @@ static void singlesocket(struct Curl_multi *multi,
|
|||||||
struct Curl_one_easy *easy_by_hash;
|
struct Curl_one_easy *easy_by_hash;
|
||||||
bool remove_sock_from_hash;
|
bool remove_sock_from_hash;
|
||||||
|
|
||||||
memset(&socks, 0, sizeof(socks));
|
|
||||||
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
|
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
|
||||||
socks[i] = CURL_SOCKET_BAD;
|
socks[i] = CURL_SOCKET_BAD;
|
||||||
|
|
||||||
@@ -1948,7 +1948,9 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
|
|||||||
if(data->set.one_easy->easy_conn) /* set socket event bitmask */
|
if(data->set.one_easy->easy_conn) /* set socket event bitmask */
|
||||||
data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;
|
data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;
|
||||||
|
|
||||||
|
do
|
||||||
result = multi_runsingle(multi, data->set.one_easy);
|
result = multi_runsingle(multi, data->set.one_easy);
|
||||||
|
while (CURLM_CALL_MULTI_PERFORM == result);
|
||||||
|
|
||||||
if(data->set.one_easy->easy_conn)
|
if(data->set.one_easy->easy_conn)
|
||||||
data->set.one_easy->easy_conn->cselect_bits = 0;
|
data->set.one_easy->easy_conn->cselect_bits = 0;
|
||||||
@@ -1977,7 +1979,9 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
|
|||||||
|
|
||||||
/* the first loop lap 'data' can be NULL */
|
/* the first loop lap 'data' can be NULL */
|
||||||
if(data) {
|
if(data) {
|
||||||
|
do
|
||||||
result = multi_runsingle(multi, data->set.one_easy);
|
result = multi_runsingle(multi, data->set.one_easy);
|
||||||
|
while (CURLM_CALL_MULTI_PERFORM == result);
|
||||||
|
|
||||||
if(CURLM_OK >= result)
|
if(CURLM_OK >= result)
|
||||||
/* get the socket(s) and check if the state has been changed since
|
/* get the socket(s) and check if the state has been changed since
|
||||||
@@ -2369,20 +2373,19 @@ CURLMcode curl_multi_assign(CURLM *multi_handle,
|
|||||||
return CURLM_OK;
|
return CURLM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool multi_conn_using(struct Curl_multi *multi,
|
static struct connectdata *conn_using(struct Curl_multi *multi,
|
||||||
struct SessionHandle *data)
|
struct SessionHandle *data)
|
||||||
{
|
{
|
||||||
/* any live CLOSEACTION-connections pointing to the give 'data' ? */
|
/* a connection in the connection cache pointing to the given 'data' ? */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0; i< multi->connc->num; i++) {
|
for(i=0; i< multi->connc->num; i++) {
|
||||||
if(multi->connc->connects[i] &&
|
if(multi->connc->connects[i] &&
|
||||||
(multi->connc->connects[i]->data == data) &&
|
(multi->connc->connects[i]->data == data))
|
||||||
multi->connc->connects[i]->protocol & PROT_CLOSEACTION)
|
return multi->connc->connects[i];
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the given data pointer to the list of 'closure handles' that are kept
|
/* Add the given data pointer to the list of 'closure handles' that are kept
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <unixlib.h>
|
#include <unixlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ int Curl_parsenetrc(const char *host,
|
|||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
pw= getpwuid(geteuid());
|
pw= getpwuid(geteuid());
|
||||||
if(pw) {
|
if(pw) {
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
home = decc_translate_vms(pw->pw_dir);
|
home = decc_translate_vms(pw->pw_dir);
|
||||||
#else
|
#else
|
||||||
home = pw->pw_dir;
|
home = pw->pw_dir;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
|
#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
|
||||||
#include <sys/filio.h>
|
#include <sys/filio.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -990,7 +990,9 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
|
|||||||
{
|
{
|
||||||
PRInt32 err;
|
PRInt32 err;
|
||||||
PRFileDesc *model = NULL;
|
PRFileDesc *model = NULL;
|
||||||
PRBool ssl2, ssl3, tlsv1;
|
PRBool ssl2 = PR_FALSE;
|
||||||
|
PRBool ssl3 = PR_FALSE;
|
||||||
|
PRBool tlsv1 = PR_FALSE;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||||
@@ -1106,8 +1108,6 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
|
|||||||
if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
|
if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ssl2 = ssl3 = tlsv1 = PR_FALSE;
|
|
||||||
|
|
||||||
switch (data->set.ssl.version) {
|
switch (data->set.ssl.version) {
|
||||||
default:
|
default:
|
||||||
case CURL_SSLVERSION_DEFAULT:
|
case CURL_SSLVERSION_DEFAULT:
|
||||||
|
|||||||
536
lib/pingpong.c
Normal file
536
lib/pingpong.c
Normal file
@@ -0,0 +1,536 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2009, 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.
|
||||||
|
*
|
||||||
|
* 'pingpong' is for generic back-and-forth support functions used by FTP,
|
||||||
|
* IMAP, POP3, SMTP and whatever more that likes them.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#include "urldata.h"
|
||||||
|
#include "sendf.h"
|
||||||
|
#include "select.h"
|
||||||
|
#include "progress.h"
|
||||||
|
#include "speedcheck.h"
|
||||||
|
#include "pingpong.h"
|
||||||
|
#include "multiif.h"
|
||||||
|
|
||||||
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "curl_memory.h"
|
||||||
|
/* The last #include file should be: */
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#ifdef USE_PINGPONG
|
||||||
|
|
||||||
|
/* Returns timeout in ms. 0 or negative number means the timeout has already
|
||||||
|
triggered */
|
||||||
|
long Curl_pp_state_timeout(struct pingpong *pp)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
long timeout_ms=360000; /* in milliseconds */
|
||||||
|
|
||||||
|
if(data->set.server_response_timeout )
|
||||||
|
/* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
|
||||||
|
remaining time. Also, use pp->response because SERVER_RESPONSE_TIMEOUT
|
||||||
|
is supposed to govern the response for any given server response, not
|
||||||
|
for the time from connect to the given server response. */
|
||||||
|
timeout_ms = data->set.server_response_timeout - /* timeout time */
|
||||||
|
Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
|
||||||
|
else if(data->set.timeout)
|
||||||
|
/* if timeout is requested, find out how much remaining time we have */
|
||||||
|
timeout_ms = data->set.timeout - /* timeout time */
|
||||||
|
Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
|
||||||
|
else
|
||||||
|
/* Without a requested timeout, we only wait 'response_time' seconds for
|
||||||
|
the full response to arrive before we bail out */
|
||||||
|
timeout_ms = pp->response_time -
|
||||||
|
Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
|
||||||
|
|
||||||
|
return timeout_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_pp_multi_statemach()
|
||||||
|
*
|
||||||
|
* called repeatedly until done when the multi interface is used.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_multi_statemach(struct pingpong *pp)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
||||||
|
int rc;
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
long timeout_ms = Curl_pp_state_timeout(pp);
|
||||||
|
|
||||||
|
if(timeout_ms <= 0) {
|
||||||
|
failf(data, "server response timeout");
|
||||||
|
return CURLE_OPERATION_TIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
|
||||||
|
pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
|
||||||
|
0);
|
||||||
|
|
||||||
|
if(rc == -1) {
|
||||||
|
failf(data, "select/poll error");
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
else if(rc != 0)
|
||||||
|
result = pp->statemach_act(conn);
|
||||||
|
|
||||||
|
/* if rc == 0, then select() timed out */
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_pp_easy_statemach()
|
||||||
|
*
|
||||||
|
* called repeatedly until done when the easy interface is used.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_easy_statemach(struct pingpong *pp)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
||||||
|
int rc;
|
||||||
|
long interval_ms;
|
||||||
|
long timeout_ms = Curl_pp_state_timeout(pp);
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
if(timeout_ms <=0 ) {
|
||||||
|
failf(data, "server response timeout");
|
||||||
|
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
|
||||||
|
}
|
||||||
|
|
||||||
|
interval_ms = 1000; /* use 1 second timeout intervals */
|
||||||
|
if(timeout_ms < interval_ms)
|
||||||
|
interval_ms = timeout_ms;
|
||||||
|
|
||||||
|
rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
|
||||||
|
pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
|
||||||
|
(int)interval_ms);
|
||||||
|
|
||||||
|
if(Curl_pgrsUpdate(conn))
|
||||||
|
result = CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
else
|
||||||
|
result = Curl_speedcheck(data, Curl_tvnow());
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
;
|
||||||
|
else if(rc == -1) {
|
||||||
|
failf(data, "select/poll error");
|
||||||
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
else if(rc)
|
||||||
|
result = pp->statemach_act(conn);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize stuff to prepare for reading a fresh new response */
|
||||||
|
void Curl_pp_init(struct pingpong *pp)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
pp->nread_resp = 0;
|
||||||
|
pp->linestart_resp = conn->data->state.buffer;
|
||||||
|
pp->pending_resp = TRUE;
|
||||||
|
pp->response = Curl_tvnow(); /* start response time-out now! */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* Curl_pp_sendfv()
|
||||||
|
*
|
||||||
|
* Send the formated string as a command to a pingpong server. Note that
|
||||||
|
* the string should not have any CRLF appended, as this function will
|
||||||
|
* append the necessary things itself.
|
||||||
|
*
|
||||||
|
* NOTE: we build the command in a fixed-length buffer, which sets length
|
||||||
|
* restrictions on the command!
|
||||||
|
*
|
||||||
|
* made to never block
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_vsendf(struct pingpong *pp,
|
||||||
|
const char *fmt,
|
||||||
|
va_list args)
|
||||||
|
{
|
||||||
|
ssize_t bytes_written;
|
||||||
|
/* may still not be big enough for some krb5 tokens */
|
||||||
|
#define SBUF_SIZE 1024
|
||||||
|
char s[SBUF_SIZE];
|
||||||
|
size_t write_len;
|
||||||
|
char *sptr=s;
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||||
|
enum protection_level data_sec = conn->data_prot;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vsnprintf(s, SBUF_SIZE-3, fmt, args);
|
||||||
|
|
||||||
|
strcat(s, "\r\n"); /* append a trailing CRLF */
|
||||||
|
|
||||||
|
bytes_written=0;
|
||||||
|
write_len = strlen(s);
|
||||||
|
|
||||||
|
Curl_pp_init(pp);
|
||||||
|
|
||||||
|
#ifdef CURL_DOES_CONVERSIONS
|
||||||
|
res = Curl_convert_to_network(data, s, write_len);
|
||||||
|
/* Curl_convert_to_network calls failf if unsuccessful */
|
||||||
|
if(res != CURLE_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif /* CURL_DOES_CONVERSIONS */
|
||||||
|
|
||||||
|
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||||
|
conn->data_prot = prot_cmd;
|
||||||
|
#endif
|
||||||
|
res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
|
||||||
|
&bytes_written);
|
||||||
|
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||||
|
conn->data_prot = data_sec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(CURLE_OK != res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if(conn->data->set.verbose)
|
||||||
|
Curl_debug(conn->data, CURLINFO_HEADER_OUT,
|
||||||
|
sptr, (size_t)bytes_written, conn);
|
||||||
|
|
||||||
|
if(bytes_written != (ssize_t)write_len) {
|
||||||
|
/* the whole chunk was not sent, store the rest of the data */
|
||||||
|
write_len -= bytes_written;
|
||||||
|
sptr += bytes_written;
|
||||||
|
pp->sendthis = malloc(write_len);
|
||||||
|
if(pp->sendthis) {
|
||||||
|
memcpy(pp->sendthis, sptr, write_len);
|
||||||
|
pp->sendsize = pp->sendleft = write_len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
failf(data, "out of memory");
|
||||||
|
res = CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pp->response = Curl_tvnow();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* Curl_pp_sendf()
|
||||||
|
*
|
||||||
|
* Send the formated string as a command to a pingpong server. Note that
|
||||||
|
* the string should not have any CRLF appended, as this function will
|
||||||
|
* append the necessary things itself.
|
||||||
|
*
|
||||||
|
* NOTE: we build the command in a fixed-length buffer, which sets length
|
||||||
|
* restrictions on the command!
|
||||||
|
*
|
||||||
|
* made to never block
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_sendf(struct pingpong *pp,
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
CURLcode res;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
|
||||||
|
res = Curl_pp_vsendf(pp, fmt, ap);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_pp_readresp()
|
||||||
|
*
|
||||||
|
* Reads a piece of a server response.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_readresp(curl_socket_t sockfd,
|
||||||
|
struct pingpong *pp,
|
||||||
|
int *code, /* return the server code if done */
|
||||||
|
size_t *size) /* size of the response */
|
||||||
|
{
|
||||||
|
ssize_t perline; /* count bytes per line */
|
||||||
|
bool keepon=TRUE;
|
||||||
|
ssize_t gotbytes;
|
||||||
|
char *ptr;
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
char * const buf = data->state.buffer;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
*code = 0; /* 0 for errors or not done */
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
ptr=buf + pp->nread_resp;
|
||||||
|
|
||||||
|
/* number of bytes in the current line, so far */
|
||||||
|
perline = (ssize_t)(ptr-pp->linestart_resp);
|
||||||
|
|
||||||
|
keepon=TRUE;
|
||||||
|
|
||||||
|
while((pp->nread_resp<BUFSIZE) && (keepon && !result)) {
|
||||||
|
|
||||||
|
if(pp->cache) {
|
||||||
|
/* we had data in the "cache", copy that instead of doing an actual
|
||||||
|
* read
|
||||||
|
*
|
||||||
|
* ftp->cache_size is cast to int here. This should be safe,
|
||||||
|
* because it would have been populated with something of size
|
||||||
|
* int to begin with, even though its datatype may be larger
|
||||||
|
* than an int.
|
||||||
|
*/
|
||||||
|
DEBUGASSERT((ptr+pp->cache_size) <= (buf+BUFSIZE+1));
|
||||||
|
memcpy(ptr, pp->cache, pp->cache_size);
|
||||||
|
gotbytes = pp->cache_size;
|
||||||
|
free(pp->cache); /* free the cache */
|
||||||
|
pp->cache = NULL; /* clear the pointer */
|
||||||
|
pp->cache_size = 0; /* zero the size just in case */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int res;
|
||||||
|
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||||
|
enum protection_level prot = conn->data_prot;
|
||||||
|
|
||||||
|
conn->data_prot = 0;
|
||||||
|
#endif
|
||||||
|
DEBUGASSERT((ptr+BUFSIZE-pp->nread_resp) <= (buf+BUFSIZE+1));
|
||||||
|
res = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp,
|
||||||
|
&gotbytes);
|
||||||
|
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||||
|
conn->data_prot = prot;
|
||||||
|
#endif
|
||||||
|
if(res < 0)
|
||||||
|
/* EWOULDBLOCK */
|
||||||
|
return CURLE_OK; /* return */
|
||||||
|
|
||||||
|
#ifdef CURL_DOES_CONVERSIONS
|
||||||
|
if((res == CURLE_OK) && (gotbytes > 0)) {
|
||||||
|
/* convert from the network encoding */
|
||||||
|
res = Curl_convert_from_network(data, ptr, gotbytes);
|
||||||
|
/* Curl_convert_from_network calls failf if unsuccessful */
|
||||||
|
}
|
||||||
|
#endif /* CURL_DOES_CONVERSIONS */
|
||||||
|
|
||||||
|
if(CURLE_OK != res) {
|
||||||
|
result = (CURLcode)res; /* Set outer result variable to this error. */
|
||||||
|
keepon = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!keepon)
|
||||||
|
;
|
||||||
|
else if(gotbytes <= 0) {
|
||||||
|
keepon = FALSE;
|
||||||
|
result = CURLE_RECV_ERROR;
|
||||||
|
failf(data, "FTP response reading failed");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* we got a whole chunk of data, which can be anything from one
|
||||||
|
* byte to a set of lines and possible just a piece of the last
|
||||||
|
* line */
|
||||||
|
ssize_t i;
|
||||||
|
ssize_t clipamount = 0;
|
||||||
|
bool restart = FALSE;
|
||||||
|
|
||||||
|
data->req.headerbytecount += (long)gotbytes;
|
||||||
|
|
||||||
|
pp->nread_resp += gotbytes;
|
||||||
|
for(i = 0; i < gotbytes; ptr++, i++) {
|
||||||
|
perline++;
|
||||||
|
if(*ptr=='\n') {
|
||||||
|
/* a newline is CRLF in ftp-talk, so the CR is ignored as
|
||||||
|
the line isn't really terminated until the LF comes */
|
||||||
|
|
||||||
|
/* output debug output if that is requested */
|
||||||
|
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||||
|
if(!conn->sec_complete)
|
||||||
|
#endif
|
||||||
|
if(data->set.verbose)
|
||||||
|
Curl_debug(data, CURLINFO_HEADER_IN,
|
||||||
|
pp->linestart_resp, (size_t)perline, conn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We pass all response-lines to the callback function registered
|
||||||
|
* for "headers". The response lines can be seen as a kind of
|
||||||
|
* headers.
|
||||||
|
*/
|
||||||
|
result = Curl_client_write(conn, CLIENTWRITE_HEADER,
|
||||||
|
pp->linestart_resp, perline);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(pp->endofresp(pp, code)) {
|
||||||
|
/* This is the end of the last line, copy the last line to the
|
||||||
|
start of the buffer and zero terminate, for old times sake (and
|
||||||
|
krb4)! */
|
||||||
|
char *meow;
|
||||||
|
int n;
|
||||||
|
for(meow=pp->linestart_resp, n=0; meow<ptr; meow++, n++)
|
||||||
|
buf[n] = *meow;
|
||||||
|
*meow=0; /* zero terminate */
|
||||||
|
keepon=FALSE;
|
||||||
|
pp->linestart_resp = ptr+1; /* advance pointer */
|
||||||
|
i++; /* skip this before getting out */
|
||||||
|
|
||||||
|
*size = pp->nread_resp; /* size of the response */
|
||||||
|
pp->nread_resp = 0; /* restart */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
perline=0; /* line starts over here */
|
||||||
|
pp->linestart_resp = ptr+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!keepon && (i != gotbytes)) {
|
||||||
|
/* We found the end of the response lines, but we didn't parse the
|
||||||
|
full chunk of data we have read from the server. We therefore need
|
||||||
|
to store the rest of the data to be checked on the next invoke as
|
||||||
|
it may actually contain another end of response already! */
|
||||||
|
clipamount = gotbytes - i;
|
||||||
|
restart = TRUE;
|
||||||
|
}
|
||||||
|
else if(keepon) {
|
||||||
|
|
||||||
|
if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) {
|
||||||
|
/* We got an excessive line without newlines and we need to deal
|
||||||
|
with it. We keep the first bytes of the line then we throw
|
||||||
|
away the rest. */
|
||||||
|
infof(data, "Excessive server response line length received, %zd bytes."
|
||||||
|
" Stripping\n", gotbytes);
|
||||||
|
restart = TRUE;
|
||||||
|
|
||||||
|
/* we keep 40 bytes since all our pingpong protocols are only
|
||||||
|
interested in the first piece */
|
||||||
|
clipamount = 40;
|
||||||
|
}
|
||||||
|
else if(pp->nread_resp > BUFSIZE/2) {
|
||||||
|
/* We got a large chunk of data and there's potentially still trailing
|
||||||
|
data to take care of, so we put any such part in the "cache", clear
|
||||||
|
the buffer to make space and restart. */
|
||||||
|
clipamount = perline;
|
||||||
|
restart = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(i == gotbytes)
|
||||||
|
restart = TRUE;
|
||||||
|
|
||||||
|
if(clipamount) {
|
||||||
|
pp->cache_size = clipamount;
|
||||||
|
pp->cache = malloc(pp->cache_size);
|
||||||
|
if(pp->cache)
|
||||||
|
memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
|
||||||
|
else
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
if(restart) {
|
||||||
|
/* now reset a few variables to start over nicely from the start of
|
||||||
|
the big buffer */
|
||||||
|
pp->nread_resp = 0; /* start over from scratch in the buffer */
|
||||||
|
ptr = pp->linestart_resp = buf;
|
||||||
|
perline = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* there was data */
|
||||||
|
|
||||||
|
} /* while there's buffer left and loop is requested */
|
||||||
|
|
||||||
|
pp->pending_resp = FALSE;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Curl_pp_getsock(struct pingpong *pp,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
|
if(pp->sendleft) {
|
||||||
|
/* write mode */
|
||||||
|
return GETSOCK_WRITESOCK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read mode */
|
||||||
|
return GETSOCK_READSOCK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_pp_flushsend(struct pingpong *pp)
|
||||||
|
{
|
||||||
|
/* we have a piece of a command still left to send */
|
||||||
|
struct connectdata *conn = pp->conn;
|
||||||
|
ssize_t written;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
|
result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
|
||||||
|
pp->sendleft, pp->sendleft, &written);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(written != (ssize_t)pp->sendleft) {
|
||||||
|
/* only a fraction was sent */
|
||||||
|
pp->sendleft -= written;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
free(pp->sendthis);
|
||||||
|
pp->sendthis=NULL;
|
||||||
|
pp->sendleft = pp->sendsize = 0;
|
||||||
|
pp->response = Curl_tvnow();
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_pp_disconnect(struct pingpong *pp)
|
||||||
|
{
|
||||||
|
if(pp->cache) {
|
||||||
|
free(pp->cache);
|
||||||
|
pp->cache = NULL;
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
148
lib/pingpong.h
Normal file
148
lib/pingpong.h
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
#ifndef __PINGPONG_H
|
||||||
|
#define __PINGPONG_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2007, 2009, 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 <stdarg.h>
|
||||||
|
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \
|
||||||
|
!defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP)
|
||||||
|
#define USE_PINGPONG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* forward-declaration, this is defined in urldata.h */
|
||||||
|
struct connectdata;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'pingpong' is the generic struct used for protocols doing server<->client
|
||||||
|
* conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
|
||||||
|
*
|
||||||
|
* It holds response cache and non-blocking sending data.
|
||||||
|
*/
|
||||||
|
struct pingpong {
|
||||||
|
char *cache; /* data cache between getresponse()-calls */
|
||||||
|
size_t cache_size; /* size of cache in bytes */
|
||||||
|
size_t nread_resp; /* number of bytes currently read of a server response */
|
||||||
|
char *linestart_resp; /* line start pointer for the server response
|
||||||
|
reader function */
|
||||||
|
bool pending_resp; /* set TRUE when a server response is pending or in
|
||||||
|
progress, and is cleared once the last response is
|
||||||
|
read */
|
||||||
|
char *sendthis; /* allocated pointer to a buffer that is to be sent to the
|
||||||
|
server */
|
||||||
|
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
|
||||||
|
size_t sendsize; /* total size of the sendthis buffer */
|
||||||
|
struct timeval response; /* set to Curl_tvnow() when a command has been sent
|
||||||
|
off, used to time-out response reading */
|
||||||
|
long response_time; /* When no timeout is given, this is the amount of
|
||||||
|
seconds we await for a server response. */
|
||||||
|
|
||||||
|
struct connectdata *conn; /* points to the connectdata struct that this
|
||||||
|
belongs to */
|
||||||
|
|
||||||
|
/* Function pointers the protocols MUST implement and provide for the
|
||||||
|
pingpong layer to function */
|
||||||
|
|
||||||
|
CURLcode (*statemach_act)(struct connectdata *conn);
|
||||||
|
|
||||||
|
int (*endofresp)(struct pingpong *pp, int *code);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_pp_multi_statemach()
|
||||||
|
*
|
||||||
|
* called repeatedly until done when the multi interface is used.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_multi_statemach(struct pingpong *pp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_pp_easy_statemach()
|
||||||
|
*
|
||||||
|
* called repeatedly until done when the easy interface is used.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_easy_statemach(struct pingpong *pp);
|
||||||
|
|
||||||
|
|
||||||
|
/* initialize stuff to prepare for reading a fresh new response */
|
||||||
|
void Curl_pp_init(struct pingpong *pp);
|
||||||
|
|
||||||
|
/* Returns timeout in ms. 0 or negative number means the timeout has already
|
||||||
|
triggered */
|
||||||
|
long Curl_pp_state_timeout(struct pingpong *pp);
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* Curl_pp_sendf()
|
||||||
|
*
|
||||||
|
* Send the formated string as a command to a pingpong server. Note that
|
||||||
|
* the string should not have any CRLF appended, as this function will
|
||||||
|
* append the necessary things itself.
|
||||||
|
*
|
||||||
|
* NOTE: we build the command in a fixed-length buffer, which sets length
|
||||||
|
* restrictions on the command!
|
||||||
|
*
|
||||||
|
* made to never block
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_sendf(struct pingpong *pp,
|
||||||
|
const char *fmt, ...);
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* Curl_pp_vsendf()
|
||||||
|
*
|
||||||
|
* Send the formated string as a command to a pingpong server. Note that
|
||||||
|
* the string should not have any CRLF appended, as this function will
|
||||||
|
* append the necessary things itself.
|
||||||
|
*
|
||||||
|
* NOTE: we build the command in a fixed-length buffer, which sets length
|
||||||
|
* restrictions on the command!
|
||||||
|
*
|
||||||
|
* made to never block
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_vsendf(struct pingpong *pp,
|
||||||
|
const char *fmt,
|
||||||
|
va_list args);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_pp_readresp()
|
||||||
|
*
|
||||||
|
* Reads a piece of a server response.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pp_readresp(curl_socket_t sockfd,
|
||||||
|
struct pingpong *pp,
|
||||||
|
int *code, /* return the server code if done */
|
||||||
|
size_t *size); /* size of the response */
|
||||||
|
|
||||||
|
|
||||||
|
CURLcode Curl_pp_flushsend(struct pingpong *pp);
|
||||||
|
|
||||||
|
/* call this when a pingpong connection is disconnected */
|
||||||
|
CURLcode Curl_pp_disconnect(struct pingpong *pp);
|
||||||
|
|
||||||
|
int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
|
||||||
|
#endif /* __PINGPONG_H */
|
||||||
960
lib/pop3.c
Normal file
960
lib/pop3.c
Normal file
@@ -0,0 +1,960 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2010, 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.
|
||||||
|
*
|
||||||
|
* RFC1939 POP3 protocol
|
||||||
|
* RFC2384 POP URL Scheme
|
||||||
|
* RFC2595 Using TLS with IMAP, POP3 and ACAP
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_POP3
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.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_INET_H
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UTSNAME_H
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NETDB_H
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __VMS
|
||||||
|
#include <in.h>
|
||||||
|
#include <inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
|
||||||
|
#undef in_addr_t
|
||||||
|
#define in_addr_t unsigned long
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "urldata.h"
|
||||||
|
#include "sendf.h"
|
||||||
|
#include "easyif.h" /* for Curl_convert_... prototypes */
|
||||||
|
|
||||||
|
#include "if2ip.h"
|
||||||
|
#include "hostip.h"
|
||||||
|
#include "progress.h"
|
||||||
|
#include "transfer.h"
|
||||||
|
#include "escape.h"
|
||||||
|
#include "http.h" /* for HTTP proxy tunnel stuff */
|
||||||
|
#include "socks.h"
|
||||||
|
#include "pop3.h"
|
||||||
|
|
||||||
|
#include "strtoofft.h"
|
||||||
|
#include "strequal.h"
|
||||||
|
#include "sslgen.h"
|
||||||
|
#include "connect.h"
|
||||||
|
#include "strerror.h"
|
||||||
|
#include "select.h"
|
||||||
|
#include "multiif.h"
|
||||||
|
#include "url.h"
|
||||||
|
#include "rawstr.h"
|
||||||
|
#include "strtoofft.h"
|
||||||
|
|
||||||
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "curl_memory.h"
|
||||||
|
/* The last #include file should be: */
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
/* Local API functions */
|
||||||
|
static CURLcode pop3_parse_url_path(struct connectdata *conn);
|
||||||
|
static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode pop3_do(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode pop3_done(struct connectdata *conn,
|
||||||
|
CURLcode, bool premature);
|
||||||
|
static CURLcode pop3_connect(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode pop3_disconnect(struct connectdata *conn);
|
||||||
|
static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
|
||||||
|
static int pop3_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
static CURLcode pop3_doing(struct connectdata *conn,
|
||||||
|
bool *dophase_done);
|
||||||
|
static CURLcode pop3_setup_connection(struct connectdata * conn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POP3 protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct Curl_handler Curl_handler_pop3 = {
|
||||||
|
"POP3", /* scheme */
|
||||||
|
pop3_setup_connection, /* setup_connection */
|
||||||
|
pop3_do, /* do_it */
|
||||||
|
pop3_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
pop3_connect, /* connect_it */
|
||||||
|
pop3_multi_statemach, /* connecting */
|
||||||
|
pop3_doing, /* doing */
|
||||||
|
pop3_getsock, /* proto_getsock */
|
||||||
|
pop3_getsock, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
pop3_disconnect, /* disconnect */
|
||||||
|
PORT_POP3, /* defport */
|
||||||
|
PROT_POP3 /* protocol */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_SSL
|
||||||
|
/*
|
||||||
|
* POP3S protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct Curl_handler Curl_handler_pop3s = {
|
||||||
|
"POP3S", /* scheme */
|
||||||
|
pop3_setup_connection, /* setup_connection */
|
||||||
|
pop3_do, /* do_it */
|
||||||
|
pop3_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
pop3_connect, /* connect_it */
|
||||||
|
pop3_multi_statemach, /* connecting */
|
||||||
|
pop3_doing, /* doing */
|
||||||
|
pop3_getsock, /* proto_getsock */
|
||||||
|
pop3_getsock, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
pop3_disconnect, /* disconnect */
|
||||||
|
PORT_POP3S, /* defport */
|
||||||
|
PROT_POP3 | PROT_POP3S | PROT_SSL /* protocol */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_HTTP
|
||||||
|
/*
|
||||||
|
* HTTP-proxyed POP3 protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct Curl_handler Curl_handler_pop3_proxy = {
|
||||||
|
"POP3", /* scheme */
|
||||||
|
ZERO_NULL, /* setup_connection */
|
||||||
|
Curl_http, /* do_it */
|
||||||
|
Curl_http_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
ZERO_NULL, /* connect_it */
|
||||||
|
ZERO_NULL, /* connecting */
|
||||||
|
ZERO_NULL, /* doing */
|
||||||
|
ZERO_NULL, /* proto_getsock */
|
||||||
|
ZERO_NULL, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
ZERO_NULL, /* disconnect */
|
||||||
|
PORT_POP3, /* defport */
|
||||||
|
PROT_HTTP /* protocol */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_SSL
|
||||||
|
/*
|
||||||
|
* HTTP-proxyed POP3S protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct Curl_handler Curl_handler_pop3s_proxy = {
|
||||||
|
"POP3S", /* scheme */
|
||||||
|
ZERO_NULL, /* setup_connection */
|
||||||
|
Curl_http, /* do_it */
|
||||||
|
Curl_http_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
ZERO_NULL, /* connect_it */
|
||||||
|
ZERO_NULL, /* connecting */
|
||||||
|
ZERO_NULL, /* doing */
|
||||||
|
ZERO_NULL, /* proto_getsock */
|
||||||
|
ZERO_NULL, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
ZERO_NULL, /* disconnect */
|
||||||
|
PORT_POP3S, /* defport */
|
||||||
|
PROT_HTTP /* protocol */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* function that checks for a pop3 status code at the start of the given
|
||||||
|
string */
|
||||||
|
static int pop3_endofresp(struct pingpong *pp,
|
||||||
|
int *resp)
|
||||||
|
{
|
||||||
|
char *line = pp->linestart_resp;
|
||||||
|
size_t len = pp->nread_resp;
|
||||||
|
|
||||||
|
if( ((len >= 3) && !memcmp("+OK", line, 3)) ||
|
||||||
|
((len >= 4) && !memcmp("-ERR", line, 4)) ) {
|
||||||
|
*resp=line[1]; /* O or E */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE; /* nothing for us */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the ONLY way to change POP3 state! */
|
||||||
|
static void state(struct connectdata *conn,
|
||||||
|
pop3state newstate)
|
||||||
|
{
|
||||||
|
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||||
|
/* for debug purposes */
|
||||||
|
static const char * const names[]={
|
||||||
|
"STOP",
|
||||||
|
"SERVERGREET",
|
||||||
|
"USER",
|
||||||
|
"PASS",
|
||||||
|
"STARTTLS",
|
||||||
|
"RETR",
|
||||||
|
"QUIT",
|
||||||
|
/* LAST */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||||
|
if(pop3c->state != newstate)
|
||||||
|
infof(conn->data, "POP3 %p state change from %s to %s\n",
|
||||||
|
pop3c, names[pop3c->state], names[newstate]);
|
||||||
|
#endif
|
||||||
|
pop3c->state = newstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode pop3_state_user(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
struct FTP *pop3 = conn->data->state.proto.pop3;
|
||||||
|
|
||||||
|
/* send USER */
|
||||||
|
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
|
||||||
|
pop3->user?pop3->user:"");
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, POP3_USER);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the POP3 "protocol connect" and "doing" phases only */
|
||||||
|
static int pop3_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for STARTTLS responses */
|
||||||
|
static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
|
||||||
|
int pop3code,
|
||||||
|
pop3state instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(pop3code != 'O') {
|
||||||
|
failf(data, "STARTTLS denied. %c", pop3code);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Curl_ssl_connect is BLOCKING */
|
||||||
|
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
conn->protocol |= PROT_POP3S;
|
||||||
|
result = pop3_state_user(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state(conn, POP3_STOP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for USER responses */
|
||||||
|
static CURLcode pop3_state_user_resp(struct connectdata *conn,
|
||||||
|
int pop3code,
|
||||||
|
pop3state instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *pop3 = data->state.proto.pop3;
|
||||||
|
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(pop3code != 'O') {
|
||||||
|
failf(data, "Access denied. %c", pop3code);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send PASS */
|
||||||
|
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
|
||||||
|
pop3->passwd?pop3->passwd:"");
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, POP3_PASS);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for PASS responses */
|
||||||
|
static CURLcode pop3_state_pass_resp(struct connectdata *conn,
|
||||||
|
int pop3code,
|
||||||
|
pop3state instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(pop3code != 'O') {
|
||||||
|
failf(data, "Access denied. %c", pop3code);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
state(conn, POP3_STOP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the retr response */
|
||||||
|
static CURLcode pop3_state_retr_resp(struct connectdata *conn,
|
||||||
|
int pop3code,
|
||||||
|
pop3state instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *pop3 = data->state.proto.pop3;
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
struct pingpong *pp = &pop3c->pp;
|
||||||
|
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if('O' != pop3code) {
|
||||||
|
state(conn, POP3_STOP);
|
||||||
|
return CURLE_RECV_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* POP3 download */
|
||||||
|
result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE,
|
||||||
|
pop3->bytecountp,
|
||||||
|
-1, NULL); /* no upload here */
|
||||||
|
|
||||||
|
if(pp->cache) {
|
||||||
|
/* At this point there is a bunch of data in the header "cache" that is
|
||||||
|
actually body content, send it as body and then skip it. Do note
|
||||||
|
that there may even be additional "headers" after the body. */
|
||||||
|
|
||||||
|
/* we may get the EOB already here! */
|
||||||
|
result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* cache is drained */
|
||||||
|
free(pp->cache);
|
||||||
|
pp->cache = NULL;
|
||||||
|
pp->cache_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
state(conn, POP3_STOP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start the DO phase */
|
||||||
|
static CURLcode pop3_retr(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
|
||||||
|
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "RETR %s", pop3c->mailbox);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, POP3_RETR);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode pop3_statemach_act(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
int pop3code;
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
struct pingpong *pp = &pop3c->pp;
|
||||||
|
size_t nread = 0;
|
||||||
|
|
||||||
|
if(pp->sendleft)
|
||||||
|
return Curl_pp_flushsend(pp);
|
||||||
|
|
||||||
|
/* we read a piece of response */
|
||||||
|
result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(pop3code) {
|
||||||
|
/* we have now received a full POP3 server response */
|
||||||
|
switch(pop3c->state) {
|
||||||
|
case POP3_SERVERGREET:
|
||||||
|
if(pop3code != 'O') {
|
||||||
|
failf(data, "Got unexpected pop3-server response");
|
||||||
|
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
|
||||||
|
/* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
|
||||||
|
to TLS connection now */
|
||||||
|
result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", NULL);
|
||||||
|
state(conn, POP3_STARTTLS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = pop3_state_user(conn);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP3_USER:
|
||||||
|
result = pop3_state_user_resp(conn, pop3code, pop3c->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP3_PASS:
|
||||||
|
result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP3_STARTTLS:
|
||||||
|
result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP3_RETR:
|
||||||
|
result = pop3_state_retr_resp(conn, pop3code, pop3c->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP3_QUIT:
|
||||||
|
/* fallthrough, just stop! */
|
||||||
|
default:
|
||||||
|
/* internal error */
|
||||||
|
state(conn, POP3_STOP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called repeatedly until done from multi.c */
|
||||||
|
static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
CURLcode result = Curl_pp_multi_statemach(&pop3c->pp);
|
||||||
|
|
||||||
|
*done = (bool)(pop3c->state == POP3_STOP);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode pop3_easy_statemach(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
struct pingpong *pp = &pop3c->pp;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
while(pop3c->state != POP3_STOP) {
|
||||||
|
result = Curl_pp_easy_statemach(pp);
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and initialize the struct POP3 for the current SessionHandle. If
|
||||||
|
* need be.
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_init(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *pop3 = data->state.proto.pop3;
|
||||||
|
if(!pop3) {
|
||||||
|
pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1);
|
||||||
|
if(!pop3)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get some initial data into the pop3 struct */
|
||||||
|
pop3->bytecountp = &data->req.bytecount;
|
||||||
|
|
||||||
|
/* No need to duplicate user+password, the connectdata struct won't change
|
||||||
|
during a session, but we re-init them here since on subsequent inits
|
||||||
|
since the conn struct may have changed or been replaced.
|
||||||
|
*/
|
||||||
|
pop3->user = conn->user;
|
||||||
|
pop3->passwd = conn->passwd;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pop3_connect() should do everything that is to be considered a part of
|
||||||
|
* the connection phase.
|
||||||
|
*
|
||||||
|
* The variable 'done' points to will be TRUE if the protocol-layer connect
|
||||||
|
* phase is done when this function returns, or FALSE is not. When called as
|
||||||
|
* a part of the easy interface, it will always be TRUE.
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_connect(struct connectdata *conn,
|
||||||
|
bool *done) /* see description above */
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
struct pingpong *pp = &pop3c->pp;
|
||||||
|
|
||||||
|
*done = FALSE; /* default to not done yet */
|
||||||
|
|
||||||
|
/* If there already is a protocol-specific struct allocated for this
|
||||||
|
sessionhandle, deal with it */
|
||||||
|
Curl_reset_reqproto(conn);
|
||||||
|
|
||||||
|
result = pop3_init(conn);
|
||||||
|
if(CURLE_OK != result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* We always support persistant connections on pop3 */
|
||||||
|
conn->bits.close = FALSE;
|
||||||
|
|
||||||
|
pp->response_time = RESP_TIMEOUT; /* set default response time-out */
|
||||||
|
pp->statemach_act = pop3_statemach_act;
|
||||||
|
pp->endofresp = pop3_endofresp;
|
||||||
|
pp->conn = conn;
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
|
||||||
|
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||||||
|
/* for POP3 over HTTP proxy */
|
||||||
|
struct HTTP http_proxy;
|
||||||
|
struct FTP *pop3_save;
|
||||||
|
|
||||||
|
/* BLOCKING */
|
||||||
|
/* We want "seamless" POP3 operations through HTTP proxy tunnel */
|
||||||
|
|
||||||
|
/* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
|
||||||
|
* conn->proto.http; we want POP3 through HTTP and we have to change the
|
||||||
|
* member temporarily for connecting to the HTTP proxy. After
|
||||||
|
* Curl_proxyCONNECT we have to set back the member to the original struct
|
||||||
|
* POP3 pointer
|
||||||
|
*/
|
||||||
|
pop3_save = data->state.proto.pop3;
|
||||||
|
memset(&http_proxy, 0, sizeof(http_proxy));
|
||||||
|
data->state.proto.http = &http_proxy;
|
||||||
|
|
||||||
|
result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
|
||||||
|
conn->host.name, conn->remote_port);
|
||||||
|
|
||||||
|
data->state.proto.pop3 = pop3_save;
|
||||||
|
|
||||||
|
if(CURLE_OK != result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
|
||||||
|
|
||||||
|
if(conn->protocol & PROT_POP3S) {
|
||||||
|
/* BLOCKING */
|
||||||
|
/* POP3S is simply pop3 with SSL for the control channel */
|
||||||
|
/* now, perform the SSL initialization for this socket */
|
||||||
|
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Curl_pp_init(pp); /* init the response reader stuff */
|
||||||
|
|
||||||
|
/* When we connect, we start in the state where we await the server greet
|
||||||
|
response */
|
||||||
|
state(conn, POP3_SERVERGREET);
|
||||||
|
|
||||||
|
if(data->state.used_interface == Curl_if_multi)
|
||||||
|
result = pop3_multi_statemach(conn, done);
|
||||||
|
else {
|
||||||
|
result = pop3_easy_statemach(conn);
|
||||||
|
if(!result)
|
||||||
|
*done = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_done()
|
||||||
|
*
|
||||||
|
* The DONE function. This does what needs to be done after a single DO has
|
||||||
|
* performed.
|
||||||
|
*
|
||||||
|
* Input argument is already checked for validity.
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
|
||||||
|
bool premature)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *pop3 = data->state.proto.pop3;
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
(void)premature;
|
||||||
|
|
||||||
|
if(!pop3)
|
||||||
|
/* When the easy handle is removed from the multi while libcurl is still
|
||||||
|
* trying to resolve the host name, it seems that the pop3 struct is not
|
||||||
|
* yet initialized, but the removal action calls Curl_done() which calls
|
||||||
|
* this function. So we simply return success if no pop3 pointer is set.
|
||||||
|
*/
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
|
if(status) {
|
||||||
|
conn->bits.close = TRUE; /* marked for closure */
|
||||||
|
result = status; /* use the already set error code */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear these for next connection */
|
||||||
|
pop3->transfer = FTPTRANSFER_BODY;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_perform()
|
||||||
|
*
|
||||||
|
* This is the actual DO function for POP3. Get a file/directory according to
|
||||||
|
* the options previously setup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode pop3_perform(struct connectdata *conn,
|
||||||
|
bool *connected, /* connect status after PASV / PORT */
|
||||||
|
bool *dophase_done)
|
||||||
|
{
|
||||||
|
/* this is POP3 and no proxy */
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
|
||||||
|
DEBUGF(infof(conn->data, "DO phase starts\n"));
|
||||||
|
|
||||||
|
if(conn->data->set.opt_no_body) {
|
||||||
|
/* requested no body means no transfer... */
|
||||||
|
struct FTP *pop3 = conn->data->state.proto.pop3;
|
||||||
|
pop3->transfer = FTPTRANSFER_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dophase_done = FALSE; /* not done yet */
|
||||||
|
|
||||||
|
/* start the first command in the DO phase */
|
||||||
|
result = pop3_retr(conn);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* run the state-machine */
|
||||||
|
if(conn->data->state.used_interface == Curl_if_multi)
|
||||||
|
result = pop3_multi_statemach(conn, dophase_done);
|
||||||
|
else {
|
||||||
|
result = pop3_easy_statemach(conn);
|
||||||
|
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||||
|
}
|
||||||
|
*connected = conn->bits.tcpconnect;
|
||||||
|
|
||||||
|
if(*dophase_done)
|
||||||
|
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_do()
|
||||||
|
*
|
||||||
|
* This function is registered as 'curl_do' function. It decodes the path
|
||||||
|
* parts etc as a wrapper to the actual DO function (pop3_perform).
|
||||||
|
*
|
||||||
|
* The input argument is already checked for validity.
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_do(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
CURLcode retcode = CURLE_OK;
|
||||||
|
|
||||||
|
*done = FALSE; /* default to false */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Since connections can be re-used between SessionHandles, this might be a
|
||||||
|
connection already existing but on a fresh SessionHandle struct so we must
|
||||||
|
make sure we have a good 'struct POP3' to play with. For new connections,
|
||||||
|
the struct POP3 is allocated and setup in the pop3_connect() function.
|
||||||
|
*/
|
||||||
|
Curl_reset_reqproto(conn);
|
||||||
|
retcode = pop3_init(conn);
|
||||||
|
if(retcode)
|
||||||
|
return retcode;
|
||||||
|
|
||||||
|
retcode = pop3_parse_url_path(conn);
|
||||||
|
if(retcode)
|
||||||
|
return retcode;
|
||||||
|
|
||||||
|
retcode = pop3_regular_transfer(conn, done);
|
||||||
|
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_quit()
|
||||||
|
*
|
||||||
|
* This should be called before calling sclose(). We should then wait for the
|
||||||
|
* response from the server before returning. The calling code should then try
|
||||||
|
* to close the connection.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_quit(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
state(conn, POP3_QUIT);
|
||||||
|
|
||||||
|
result = pop3_easy_statemach(conn);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_disconnect()
|
||||||
|
*
|
||||||
|
* Disconnect from an POP3 server. Cleanup protocol-specific per-connection
|
||||||
|
* resources. BLOCKING.
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_disconnect(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct pop3_conn *pop3c= &conn->proto.pop3c;
|
||||||
|
|
||||||
|
/* We cannot send quit unconditionally. If this connection is stale or
|
||||||
|
bad in any way, sending quit and waiting around here will make the
|
||||||
|
disconnect wait in vain and cause more problems than we need to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The POP3 session may or may not have been allocated/setup at this
|
||||||
|
point! */
|
||||||
|
(void)pop3_quit(conn); /* ignore errors on the LOGOUT */
|
||||||
|
|
||||||
|
|
||||||
|
Curl_pp_disconnect(&pop3c->pp);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_parse_url_path()
|
||||||
|
*
|
||||||
|
* Parse the URL path into separate path components.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static CURLcode pop3_parse_url_path(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
/* the pop3 struct is already inited in pop3_connect() */
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
const char *path = data->state.path;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if(!*path)
|
||||||
|
path = "INBOX";
|
||||||
|
|
||||||
|
/* url decode the path and use this mailbox */
|
||||||
|
pop3c->mailbox = curl_easy_unescape(data, path, 0, &len);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call this when the DO phase has completed */
|
||||||
|
static CURLcode pop3_dophase_done(struct connectdata *conn,
|
||||||
|
bool connected)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct FTP *pop3 = conn->data->state.proto.pop3;
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
(void)connected;
|
||||||
|
|
||||||
|
if(pop3->transfer != FTPTRANSFER_BODY)
|
||||||
|
/* no data to transfer */
|
||||||
|
result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
|
||||||
|
free(pop3c->mailbox);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called from multi.c while DOing */
|
||||||
|
static CURLcode pop3_doing(struct connectdata *conn,
|
||||||
|
bool *dophase_done)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
result = pop3_multi_statemach(conn, dophase_done);
|
||||||
|
|
||||||
|
if(*dophase_done) {
|
||||||
|
result = pop3_dophase_done(conn, FALSE /* not connected */);
|
||||||
|
|
||||||
|
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* pop3_regular_transfer()
|
||||||
|
*
|
||||||
|
* The input argument is already checked for validity.
|
||||||
|
*
|
||||||
|
* Performs all commands done before a regular transfer between a local and a
|
||||||
|
* remote host.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
CURLcode pop3_regular_transfer(struct connectdata *conn,
|
||||||
|
bool *dophase_done)
|
||||||
|
{
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
bool connected=FALSE;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
data->req.size = -1; /* make sure this is unknown at this point */
|
||||||
|
|
||||||
|
Curl_pgrsSetUploadCounter(data, 0);
|
||||||
|
Curl_pgrsSetDownloadCounter(data, 0);
|
||||||
|
Curl_pgrsSetUploadSize(data, 0);
|
||||||
|
Curl_pgrsSetDownloadSize(data, 0);
|
||||||
|
|
||||||
|
result = pop3_perform(conn,
|
||||||
|
&connected, /* have we connected after PASV/PORT */
|
||||||
|
dophase_done); /* all commands in the DO-phase done? */
|
||||||
|
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
|
||||||
|
if(!*dophase_done)
|
||||||
|
/* the DO phase has not completed yet */
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
|
result = pop3_dophase_done(conn, connected);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode pop3_setup_connection(struct connectdata * conn)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
|
||||||
|
/* Unless we have asked to tunnel pop3 operations through the proxy, we
|
||||||
|
switch and use HTTP operations only */
|
||||||
|
#ifndef CURL_DISABLE_HTTP
|
||||||
|
if(conn->handler == &Curl_handler_pop3)
|
||||||
|
conn->handler = &Curl_handler_pop3_proxy;
|
||||||
|
else {
|
||||||
|
#ifdef USE_SSL
|
||||||
|
conn->handler = &Curl_handler_pop3s_proxy;
|
||||||
|
#else
|
||||||
|
failf(data, "POP3S not supported!");
|
||||||
|
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We explicitly mark this connection as persistent here as we're doing
|
||||||
|
* POP3 over HTTP and thus we accidentally avoid setting this value
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
conn->bits.close = FALSE;
|
||||||
|
#else
|
||||||
|
failf(data, "POP3 over http proxy requires HTTP support built-in!");
|
||||||
|
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
data->state.path++; /* don't include the initial slash */
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is the 5-bytes End-Of-Body marker for POP3 */
|
||||||
|
#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
|
||||||
|
#define POP3_EOB_LEN 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function scans the body after the end-of-body and writes everything
|
||||||
|
* until the end is found.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pop3_write(struct connectdata *conn,
|
||||||
|
char *str,
|
||||||
|
size_t nread)
|
||||||
|
{
|
||||||
|
/* This code could be made into a special function in the handler struct. */
|
||||||
|
CURLcode result;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct SingleRequest *k = &data->req;
|
||||||
|
|
||||||
|
/* Detect the end-of-body marker, which is 5 bytes:
|
||||||
|
0d 0a 2e 0d 0a. This marker can of course be spread out
|
||||||
|
over up to 5 different data chunks. Deal with it! */
|
||||||
|
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||||
|
int checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread);
|
||||||
|
int checkleft = POP3_EOB_LEN-pop3c->eob;
|
||||||
|
int check = (checkmax >= checkleft?checkleft:checkmax);
|
||||||
|
|
||||||
|
if(!memcmp(POP3_EOB, &str[nread - check], check)) {
|
||||||
|
/* substring match */
|
||||||
|
pop3c->eob += check;
|
||||||
|
if(pop3c->eob == POP3_EOB_LEN) {
|
||||||
|
/* full match, the transfer is done! */
|
||||||
|
str[nread - check] = '\0';
|
||||||
|
nread -= check;
|
||||||
|
k->keepon &= ~KEEP_RECV;
|
||||||
|
pop3c->eob = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(pop3c->eob) {
|
||||||
|
/* not a match, but we matched a piece before so we must now
|
||||||
|
send that part as body first, before we move on and send
|
||||||
|
this buffer */
|
||||||
|
result = Curl_client_write(conn, CLIENTWRITE_BODY,
|
||||||
|
(char *)POP3_EOB, pop3c->eob);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
pop3c->eob = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CURL_DISABLE_POP3 */
|
||||||
62
lib/pop3.h
Normal file
62
lib/pop3.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef __POP3_H
|
||||||
|
#define __POP3_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, 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$
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* POP3 unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
typedef enum {
|
||||||
|
POP3_STOP, /* do nothing state, stops the state machine */
|
||||||
|
POP3_SERVERGREET, /* waiting for the initial greeting immediately after
|
||||||
|
a connect */
|
||||||
|
POP3_USER,
|
||||||
|
POP3_PASS,
|
||||||
|
POP3_STARTTLS,
|
||||||
|
POP3_RETR,
|
||||||
|
POP3_QUIT,
|
||||||
|
POP3_LAST /* never used */
|
||||||
|
} pop3state;
|
||||||
|
|
||||||
|
/* pop3_conn is used for struct connection-oriented data in the connectdata
|
||||||
|
struct */
|
||||||
|
struct pop3_conn {
|
||||||
|
struct pingpong pp;
|
||||||
|
char *mailbox; /* what to RETR */
|
||||||
|
int eob; /* number of bytes of the EOB (End Of Body) that has been
|
||||||
|
received thus far */
|
||||||
|
pop3state state; /* always use pop3.c:state() to change state! */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct Curl_handler Curl_handler_pop3;
|
||||||
|
extern const struct Curl_handler Curl_handler_pop3s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function scans the body after the end-of-body and writes everything
|
||||||
|
* until the end is found.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_pop3_write(struct connectdata *conn,
|
||||||
|
char *str,
|
||||||
|
size_t nread);
|
||||||
|
|
||||||
|
#endif /* __POP3_H */
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -289,7 +289,7 @@ static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* An SSL error. */
|
/* An SSL error. */
|
||||||
failf(data, "SSL_Destroy() returned error %d", SSL_Strerror(rc, NULL));
|
failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* An SSL error. */
|
/* An SSL error. */
|
||||||
failf(conn->data, "SSL_Write() returned error %d",
|
failf(conn->data, "SSL_Write() returned error %s",
|
||||||
SSL_Strerror(rc, NULL));
|
SSL_Strerror(rc, NULL));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
755
lib/rtsp.c
Normal file
755
lib/rtsp.c
Normal file
@@ -0,0 +1,755 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2010, 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_RTSP
|
||||||
|
|
||||||
|
#include "urldata.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "transfer.h"
|
||||||
|
#include "sendf.h"
|
||||||
|
#include "easyif.h" /* for Curl_convert_... prototypes */
|
||||||
|
#include "multiif.h"
|
||||||
|
#include "http.h"
|
||||||
|
#include "url.h"
|
||||||
|
#include "progress.h"
|
||||||
|
#include "rtsp.h"
|
||||||
|
#include "rawstr.h"
|
||||||
|
#include "curl_memory.h"
|
||||||
|
|
||||||
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
/* The last #include file should be: */
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO (general)
|
||||||
|
* -incoming server requests
|
||||||
|
* -server CSeq counter
|
||||||
|
* -digest authentication
|
||||||
|
* -connect thru proxy
|
||||||
|
* -pipelining?
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1])))
|
||||||
|
|
||||||
|
#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \
|
||||||
|
((int)((unsigned char)((p)[3]))))
|
||||||
|
|
||||||
|
static int rtsp_getsock_do(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
|
||||||
|
/* this returns the socket to wait for in the DO and DOING state for the multi
|
||||||
|
interface and then we're always _sending_ a request and thus we wait for
|
||||||
|
the single socket to become writable only */
|
||||||
|
static int rtsp_getsock_do(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
/* write mode */
|
||||||
|
(void)numsocks; /* unused, we trust it to be at least 1 */
|
||||||
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
return GETSOCK_WRITESOCK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTSP handler interface.
|
||||||
|
*/
|
||||||
|
const struct Curl_handler Curl_handler_rtsp = {
|
||||||
|
"RTSP", /* scheme */
|
||||||
|
ZERO_NULL, /* setup_connection */
|
||||||
|
Curl_rtsp, /* do_it */
|
||||||
|
Curl_rtsp_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
Curl_rtsp_connect, /* connect_it */
|
||||||
|
ZERO_NULL, /* connecting */
|
||||||
|
ZERO_NULL, /* doing */
|
||||||
|
ZERO_NULL, /* proto_getsock */
|
||||||
|
rtsp_getsock_do, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
Curl_rtsp_disconnect, /* disconnect */
|
||||||
|
PORT_RTSP, /* defport */
|
||||||
|
PROT_RTSP, /* protocol */
|
||||||
|
};
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
CURLcode httpStatus;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
httpStatus = Curl_http_connect(conn, done);
|
||||||
|
|
||||||
|
/* Initialize the CSeq if not already done */
|
||||||
|
if(data->state.rtsp_next_client_CSeq == 0)
|
||||||
|
data->state.rtsp_next_client_CSeq = 1;
|
||||||
|
if(data->state.rtsp_next_server_CSeq == 0)
|
||||||
|
data->state.rtsp_next_server_CSeq = 1;
|
||||||
|
|
||||||
|
conn->proto.rtspc.rtp_channel = -1;
|
||||||
|
|
||||||
|
return httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp_disconnect(struct connectdata *conn) {
|
||||||
|
Curl_safefree(conn->proto.rtspc.rtp_buf);
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp_done(struct connectdata *conn,
|
||||||
|
CURLcode status, bool premature)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct RTSP *rtsp = data->state.proto.rtsp;
|
||||||
|
CURLcode httpStatus;
|
||||||
|
long CSeq_sent;
|
||||||
|
long CSeq_recv;
|
||||||
|
|
||||||
|
/* Bypass HTTP empty-reply checks on receive */
|
||||||
|
if(data->set.rtspreq == RTSPREQ_RECEIVE)
|
||||||
|
premature = TRUE;
|
||||||
|
|
||||||
|
httpStatus = Curl_http_done(conn, status, premature);
|
||||||
|
|
||||||
|
if(rtsp) {
|
||||||
|
/* Check the sequence numbers */
|
||||||
|
CSeq_sent = rtsp->CSeq_sent;
|
||||||
|
CSeq_recv = rtsp->CSeq_recv;
|
||||||
|
if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) {
|
||||||
|
failf(data, "The CSeq of this request %ld did not match the response %ld",
|
||||||
|
CSeq_sent, CSeq_recv);
|
||||||
|
return CURLE_RTSP_CSEQ_ERROR;
|
||||||
|
}
|
||||||
|
else if(data->set.rtspreq == RTSPREQ_RECEIVE &&
|
||||||
|
(conn->proto.rtspc.rtp_channel == -1)) {
|
||||||
|
infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
|
||||||
|
/* TODO CPC: Server -> Client logic here */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
Curl_RtspReq rtspreq = data->set.rtspreq;
|
||||||
|
struct RTSP *rtsp;
|
||||||
|
struct HTTP *http;
|
||||||
|
Curl_send_buffer *req_buffer;
|
||||||
|
curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
|
||||||
|
curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
|
||||||
|
|
||||||
|
const char *p_request = NULL;
|
||||||
|
const char *p_session_id = NULL;
|
||||||
|
const char *p_accept = NULL;
|
||||||
|
const char *p_accept_encoding = NULL;
|
||||||
|
const char *p_range = NULL;
|
||||||
|
const char *p_referrer = NULL;
|
||||||
|
const char *p_stream_uri = NULL;
|
||||||
|
const char *p_transport = NULL;
|
||||||
|
const char *p_uagent = NULL;
|
||||||
|
|
||||||
|
*done = TRUE;
|
||||||
|
|
||||||
|
Curl_reset_reqproto(conn);
|
||||||
|
|
||||||
|
if(!data->state.proto.rtsp) {
|
||||||
|
/* Only allocate this struct if we don't already have it! */
|
||||||
|
|
||||||
|
rtsp = calloc(1, sizeof(struct RTSP));
|
||||||
|
if(!rtsp)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
data->state.proto.rtsp = rtsp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rtsp = data->state.proto.rtsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
http = &(rtsp->http_wrapper);
|
||||||
|
/* Assert that no one has changed the RTSP struct in an evil way */
|
||||||
|
DEBUGASSERT((void *)http == (void *)rtsp);
|
||||||
|
|
||||||
|
rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
|
||||||
|
rtsp->CSeq_recv = 0;
|
||||||
|
|
||||||
|
/* Setup the 'p_request' pointer to the proper p_request string
|
||||||
|
* Since all RTSP requests are included here, there is no need to
|
||||||
|
* support custom requests like HTTP.
|
||||||
|
**/
|
||||||
|
DEBUGASSERT((rtspreq > RTSPREQ_NONE && rtspreq < RTSPREQ_LAST));
|
||||||
|
data->set.opt_no_body = TRUE; /* most requests don't contain a body */
|
||||||
|
switch(rtspreq) {
|
||||||
|
case RTSPREQ_NONE:
|
||||||
|
failf(data, "Got invalid RTSP request: RTSPREQ_NONE");
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
case RTSPREQ_OPTIONS:
|
||||||
|
p_request = "OPTIONS";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_DESCRIBE:
|
||||||
|
p_request = "DESCRIBE";
|
||||||
|
data->set.opt_no_body = FALSE;
|
||||||
|
break;
|
||||||
|
case RTSPREQ_ANNOUNCE:
|
||||||
|
p_request = "ANNOUNCE";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_SETUP:
|
||||||
|
p_request = "SETUP";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_PLAY:
|
||||||
|
p_request = "PLAY";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_PAUSE:
|
||||||
|
p_request = "PAUSE";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_TEARDOWN:
|
||||||
|
p_request = "TEARDOWN";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_GET_PARAMETER:
|
||||||
|
p_request = "GET_PARAMETER";
|
||||||
|
data->set.opt_no_body = FALSE;
|
||||||
|
break;
|
||||||
|
case RTSPREQ_SET_PARAMETER:
|
||||||
|
p_request = "SET_PARAMETER";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_RECORD:
|
||||||
|
p_request = "RECORD";
|
||||||
|
break;
|
||||||
|
case RTSPREQ_RECEIVE:
|
||||||
|
p_request = "";
|
||||||
|
/* Treat interleaved RTP as body*/
|
||||||
|
data->set.opt_no_body = FALSE;
|
||||||
|
break;
|
||||||
|
case RTSPREQ_LAST:
|
||||||
|
failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rtspreq == RTSPREQ_RECEIVE) {
|
||||||
|
result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
|
||||||
|
&http->readbytecount, -1, NULL);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
|
||||||
|
if(!p_session_id &&
|
||||||
|
(rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
|
||||||
|
failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
|
||||||
|
p_request ? p_request : "");
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: auth? */
|
||||||
|
/* TODO: proxy? */
|
||||||
|
|
||||||
|
/* Stream URI. Default to server '*' if not specified */
|
||||||
|
if(data->set.str[STRING_RTSP_STREAM_URI]) {
|
||||||
|
p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p_stream_uri = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transport Header for SETUP requests */
|
||||||
|
p_transport = Curl_checkheaders(data, "Transport:");
|
||||||
|
if(rtspreq == RTSPREQ_SETUP && !p_transport) {
|
||||||
|
/* New Transport: setting? */
|
||||||
|
if(data->set.str[STRING_RTSP_TRANSPORT]) {
|
||||||
|
Curl_safefree(conn->allocptr.rtsp_transport);
|
||||||
|
|
||||||
|
conn->allocptr.rtsp_transport =
|
||||||
|
aprintf("Transport: %s\r\n",
|
||||||
|
data->set.str[STRING_RTSP_TRANSPORT]);
|
||||||
|
if(!conn->allocptr.rtsp_transport)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
failf(data,
|
||||||
|
"Refusing to issue an RTSP SETUP without a Transport: header.");
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_transport = conn->allocptr.rtsp_transport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accept Headers for DESCRIBE requests */
|
||||||
|
if(rtspreq == RTSPREQ_DESCRIBE) {
|
||||||
|
/* Accept Header */
|
||||||
|
p_accept = Curl_checkheaders(data, "Accept:")?
|
||||||
|
NULL:"Accept: application/sdp\r\n";
|
||||||
|
|
||||||
|
/* Accept-Encoding header */
|
||||||
|
if(!Curl_checkheaders(data, "Accept-Encoding:") &&
|
||||||
|
data->set.str[STRING_ENCODING]) {
|
||||||
|
Curl_safefree(conn->allocptr.accept_encoding);
|
||||||
|
conn->allocptr.accept_encoding =
|
||||||
|
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
|
||||||
|
|
||||||
|
if(!conn->allocptr.accept_encoding)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
p_accept_encoding = conn->allocptr.accept_encoding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default to text/parameters for GET_PARAMETER */
|
||||||
|
if(rtspreq == RTSPREQ_GET_PARAMETER) {
|
||||||
|
p_accept = Curl_checkheaders(data, "Accept:")?
|
||||||
|
NULL:"Accept: text/parameters\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The User-Agent string might have been allocated in url.c already, because
|
||||||
|
it might have been used in the proxy connect, but if we have got a header
|
||||||
|
with the user-agent string specified, we erase the previously made string
|
||||||
|
here. */
|
||||||
|
if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
|
||||||
|
Curl_safefree(conn->allocptr.uagent);
|
||||||
|
conn->allocptr.uagent = NULL;
|
||||||
|
}
|
||||||
|
else if(!Curl_checkheaders(data, "User-Agent:") &&
|
||||||
|
data->set.str[STRING_USERAGENT]) {
|
||||||
|
p_uagent = conn->allocptr.uagent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Referrer */
|
||||||
|
Curl_safefree(conn->allocptr.ref);
|
||||||
|
if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
|
||||||
|
conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
|
||||||
|
else
|
||||||
|
conn->allocptr.ref = NULL;
|
||||||
|
|
||||||
|
p_referrer = conn->allocptr.ref;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Range Header
|
||||||
|
* Only applies to PLAY, PAUSE, RECORD
|
||||||
|
*
|
||||||
|
* Go ahead and use the Range stuff supplied for HTTP
|
||||||
|
*/
|
||||||
|
if(data->state.use_range &&
|
||||||
|
(rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
|
||||||
|
|
||||||
|
/* Check to see if there is a range set in the custom headers */
|
||||||
|
if(!Curl_checkheaders(data, "Range:") && data->state.range) {
|
||||||
|
Curl_safefree(conn->allocptr.rangeline);
|
||||||
|
conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
|
||||||
|
p_range = conn->allocptr.rangeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check the custom headers
|
||||||
|
*/
|
||||||
|
if(Curl_checkheaders(data, "CSeq:")) {
|
||||||
|
failf(data, "CSeq cannot be set as a custom header.");
|
||||||
|
return CURLE_RTSP_CSEQ_ERROR;
|
||||||
|
}
|
||||||
|
if(Curl_checkheaders(data, "Session:")) {
|
||||||
|
failf(data, "Session ID cannot be set as a custom header.");
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize a dynamic send buffer */
|
||||||
|
req_buffer = Curl_add_buffer_init();
|
||||||
|
|
||||||
|
if(!req_buffer)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
result =
|
||||||
|
Curl_add_bufferf(req_buffer,
|
||||||
|
"%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
|
||||||
|
"CSeq: %ld\r\n", /* CSeq */
|
||||||
|
(p_request ? p_request : ""), p_stream_uri,
|
||||||
|
rtsp->CSeq_sent);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rather than do a normal alloc line, keep the session_id unformatted
|
||||||
|
* to make comparison easier
|
||||||
|
*/
|
||||||
|
if(p_session_id) {
|
||||||
|
result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shared HTTP-like options
|
||||||
|
*/
|
||||||
|
result = Curl_add_bufferf(req_buffer,
|
||||||
|
"%s" /* transport */
|
||||||
|
"%s" /* accept */
|
||||||
|
"%s" /* accept-encoding */
|
||||||
|
"%s" /* range */
|
||||||
|
"%s" /* referrer */
|
||||||
|
"%s" /* user-agent */
|
||||||
|
,
|
||||||
|
p_transport ? p_transport : "",
|
||||||
|
p_accept ? p_accept : "",
|
||||||
|
p_accept_encoding ? p_accept_encoding : "",
|
||||||
|
p_range ? p_range : "",
|
||||||
|
p_referrer ? p_referrer : "",
|
||||||
|
p_uagent ? p_uagent : "");
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
|
||||||
|
result = Curl_add_timecondition(data, req_buffer);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = Curl_add_custom_headers(conn, req_buffer);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(rtspreq == RTSPREQ_ANNOUNCE || rtspreq == RTSPREQ_SET_PARAMETER) {
|
||||||
|
if(data->set.upload) {
|
||||||
|
putsize = data->set.infilesize;
|
||||||
|
data->set.httpreq = HTTPREQ_PUT;
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
postsize = (data->set.postfieldsize != -1)?
|
||||||
|
data->set.postfieldsize:
|
||||||
|
(data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
|
||||||
|
data->set.httpreq = HTTPREQ_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As stated in the http comments, it is probably not wise to
|
||||||
|
* actually set a custom Content-Length in the headers */
|
||||||
|
if(!Curl_checkheaders(data, "Content-Length:")) {
|
||||||
|
result = Curl_add_bufferf(req_buffer,
|
||||||
|
"Content-Length: %" FORMAT_OFF_T"\r\n",
|
||||||
|
(data->set.upload ? putsize : postsize));
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rtspreq == RTSPREQ_SET_PARAMETER) {
|
||||||
|
if(!Curl_checkheaders(data, "Content-Type:")) {
|
||||||
|
result = Curl_add_bufferf(req_buffer,
|
||||||
|
"Content-Type: text/parameters\r\n");
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rtspreq == RTSPREQ_ANNOUNCE) {
|
||||||
|
if(!Curl_checkheaders(data, "Content-Type:")) {
|
||||||
|
result = Curl_add_bufferf(req_buffer,
|
||||||
|
"Content-Type: application/sdp\r\n");
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->state.expect100header = FALSE; /* RTSP posts are simple/small */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* RTSP never allows chunked transfer */
|
||||||
|
data->req.forbidchunk = TRUE;
|
||||||
|
/* Finish the request buffer */
|
||||||
|
result = Curl_add_buffer(req_buffer, "\r\n", 2);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(postsize > 0) {
|
||||||
|
result = Curl_add_buffer(req_buffer, data->set.postfields,
|
||||||
|
(size_t)postsize);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* issue the request */
|
||||||
|
result = Curl_add_buffer_send(req_buffer, conn,
|
||||||
|
&data->info.request_size, 0, FIRSTSOCKET);
|
||||||
|
if(result) {
|
||||||
|
failf(data, "Failed sending RTSP request");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
|
||||||
|
&http->readbytecount,
|
||||||
|
putsize?FIRSTSOCKET:-1,
|
||||||
|
putsize?&http->writebytecount:NULL);
|
||||||
|
|
||||||
|
if(result) {
|
||||||
|
failf(data, "Failed RTSP transfer");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the CSeq on success */
|
||||||
|
data->state.rtsp_next_client_CSeq++;
|
||||||
|
|
||||||
|
if(http->writebytecount) {
|
||||||
|
/* if a request-body has been sent off, we make sure this progress is
|
||||||
|
noted properly */
|
||||||
|
Curl_pgrsSetUploadCounter(data, http->writebytecount);
|
||||||
|
if(Curl_pgrsUpdate(conn))
|
||||||
|
result = CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data,
|
||||||
|
struct connectdata *conn,
|
||||||
|
ssize_t *nread,
|
||||||
|
bool *readmore) {
|
||||||
|
struct SingleRequest *k = &data->req;
|
||||||
|
struct rtsp_conn *rtspc = &(conn->proto.rtspc);
|
||||||
|
|
||||||
|
char *rtp; /* moving pointer to rtp data */
|
||||||
|
ssize_t rtp_dataleft; /* how much data left to parse in this round */
|
||||||
|
char *scratch;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
if(rtspc->rtp_buf) {
|
||||||
|
/* There was some leftover data the last time. Merge buffers */
|
||||||
|
char *newptr = realloc(rtspc->rtp_buf, rtspc->rtp_bufsize + *nread);
|
||||||
|
if(!newptr) {
|
||||||
|
Curl_safefree(rtspc->rtp_buf);
|
||||||
|
rtspc->rtp_buf = NULL;
|
||||||
|
rtspc->rtp_bufsize = 0;
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
rtspc->rtp_buf = newptr;
|
||||||
|
memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread);
|
||||||
|
rtspc->rtp_bufsize += *nread;
|
||||||
|
rtp = rtspc->rtp_buf;
|
||||||
|
rtp_dataleft = rtspc->rtp_bufsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Just parse the request buffer directly */
|
||||||
|
rtp = k->str;
|
||||||
|
rtp_dataleft = *nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((rtp_dataleft > 0) &&
|
||||||
|
(rtp[0] == '$')) {
|
||||||
|
if(rtp_dataleft > 4) {
|
||||||
|
int rtp_length;
|
||||||
|
|
||||||
|
/* Parse the header */
|
||||||
|
/* The channel identifier immediately follows and is 1 byte */
|
||||||
|
rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp);
|
||||||
|
|
||||||
|
/* The length is two bytes */
|
||||||
|
rtp_length = RTP_PKT_LENGTH(rtp);
|
||||||
|
|
||||||
|
if(rtp_dataleft < rtp_length + 4) {
|
||||||
|
/* Need more - incomplete payload*/
|
||||||
|
*readmore = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* We have the full RTP interleaved packet
|
||||||
|
* Write out the header including the leading '$' */
|
||||||
|
DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
|
||||||
|
rtspc->rtp_channel, rtp_length));
|
||||||
|
result = rtp_client_write(conn, &rtp[0], rtp_length + 4);
|
||||||
|
if(result) {
|
||||||
|
failf(data, "Got an error writing an RTP packet");
|
||||||
|
*readmore = FALSE;
|
||||||
|
Curl_safefree(rtspc->rtp_buf);
|
||||||
|
rtspc->rtp_buf = NULL;
|
||||||
|
rtspc->rtp_bufsize = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move forward in the buffer */
|
||||||
|
rtp_dataleft -= rtp_length + 4;
|
||||||
|
rtp += rtp_length + 4;
|
||||||
|
|
||||||
|
if(data->set.rtspreq == RTSPREQ_RECEIVE) {
|
||||||
|
/* If we are in a passive receive, give control back
|
||||||
|
* to the app as often as we can.
|
||||||
|
*/
|
||||||
|
k->keepon &= ~KEEP_RECV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Need more - incomplete header */
|
||||||
|
*readmore = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rtp_dataleft != 0 && rtp[0] == '$') {
|
||||||
|
DEBUGF(infof(data, "RTP Rewinding %zu %s\n", rtp_dataleft,
|
||||||
|
*readmore ? "(READMORE)" : ""));
|
||||||
|
|
||||||
|
/* Store the incomplete RTP packet for a "rewind" */
|
||||||
|
scratch = malloc(rtp_dataleft);
|
||||||
|
if(!scratch) {
|
||||||
|
Curl_safefree(rtspc->rtp_buf);
|
||||||
|
rtspc->rtp_buf = NULL;
|
||||||
|
rtspc->rtp_bufsize = 0;
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
memcpy(scratch, rtp, rtp_dataleft);
|
||||||
|
Curl_safefree(rtspc->rtp_buf);
|
||||||
|
rtspc->rtp_buf = scratch;
|
||||||
|
rtspc->rtp_bufsize = rtp_dataleft;
|
||||||
|
|
||||||
|
/* As far as the transfer is concerned, this data is consumed */
|
||||||
|
*nread = 0;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Fix up k->str to point just after the last RTP packet */
|
||||||
|
k->str += *nread - rtp_dataleft;
|
||||||
|
|
||||||
|
/* either all of the data has been read or...
|
||||||
|
* rtp now points at the next byte to parse
|
||||||
|
*/
|
||||||
|
if(rtp_dataleft > 0)
|
||||||
|
DEBUGASSERT(k->str[0] == rtp[0]);
|
||||||
|
|
||||||
|
DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */
|
||||||
|
|
||||||
|
*nread = rtp_dataleft;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here, we have finished with the leftover/merge buffer */
|
||||||
|
Curl_safefree(rtspc->rtp_buf);
|
||||||
|
rtspc->rtp_buf = NULL;
|
||||||
|
rtspc->rtp_bufsize = 0;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
size_t wrote;
|
||||||
|
curl_write_callback writeit;
|
||||||
|
|
||||||
|
if(len == 0) {
|
||||||
|
failf (data, "Cannot write a 0 size RTP packet.");
|
||||||
|
return CURLE_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
|
||||||
|
wrote = writeit(ptr, 1, len, data->set.rtp_out);
|
||||||
|
|
||||||
|
if(CURL_WRITEFUNC_PAUSE == wrote) {
|
||||||
|
failf (data, "Cannot pause RTP");
|
||||||
|
return CURLE_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wrote != len) {
|
||||||
|
failf (data, "Failed writing RTP data");
|
||||||
|
return CURLE_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
|
||||||
|
char *header)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
long CSeq = 0;
|
||||||
|
|
||||||
|
if(checkprefix("CSeq:", header)) {
|
||||||
|
/* Store the received CSeq. Match is verified in rtsp_done */
|
||||||
|
int nc;
|
||||||
|
char *temp = strdup(header);
|
||||||
|
if(!temp)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
Curl_strntoupper(temp, temp, sizeof(temp));
|
||||||
|
nc = sscanf(temp, "CSEQ: %ld", &CSeq);
|
||||||
|
free(temp);
|
||||||
|
if(nc == 1) {
|
||||||
|
data->state.proto.rtsp->CSeq_recv = CSeq; /* mark the request */
|
||||||
|
data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
failf(data, "Unable to read the CSeq header: [%s]", header);
|
||||||
|
return CURLE_RTSP_CSEQ_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(checkprefix("Session:", header)) {
|
||||||
|
char *start;
|
||||||
|
|
||||||
|
/* Find the first non-space letter */
|
||||||
|
start = header + 9;
|
||||||
|
while(*start && ISSPACE(*start))
|
||||||
|
start++;
|
||||||
|
|
||||||
|
if(!start) {
|
||||||
|
failf(data, "Got a blank Session ID");
|
||||||
|
}
|
||||||
|
else if(data->set.str[STRING_RTSP_SESSION_ID]) {
|
||||||
|
/* If the Session ID is set, then compare */
|
||||||
|
if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID],
|
||||||
|
strlen(data->set.str[STRING_RTSP_SESSION_ID])) != 0) {
|
||||||
|
failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
|
||||||
|
start, data->set.str[STRING_RTSP_SESSION_ID]);
|
||||||
|
return CURLE_RTSP_SESSION_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If the Session ID is not set, and we find it in a response, then
|
||||||
|
set it */
|
||||||
|
|
||||||
|
/* The session ID can be an alphanumeric or a 'safe' character
|
||||||
|
*
|
||||||
|
* RFC 2326 15.1 Base Syntax:
|
||||||
|
* safe = "\$" | "-" | "_" | "." | "+"
|
||||||
|
* */
|
||||||
|
char *end = start;
|
||||||
|
while(*end &&
|
||||||
|
(ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' ||
|
||||||
|
*end == '+' ||
|
||||||
|
(*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1))))
|
||||||
|
end++;
|
||||||
|
|
||||||
|
/* Copy the id substring into a new buffer */
|
||||||
|
data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1);
|
||||||
|
if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start);
|
||||||
|
(data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CURL_DISABLE_RTSP */
|
||||||
83
lib/rtsp.h
Normal file
83
lib/rtsp.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#ifndef __RTSP_H_
|
||||||
|
#define __RTSP_H_
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2010, 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_RTSP
|
||||||
|
|
||||||
|
extern const struct Curl_handler Curl_handler_rtsp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse and write out any available RTP data.
|
||||||
|
*
|
||||||
|
* nread: amount of data left after k->str. will be modified if RTP
|
||||||
|
* data is parsed and k->str is moved up
|
||||||
|
* readmore: whether or not the RTP parser needs more data right away
|
||||||
|
*/
|
||||||
|
CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data,
|
||||||
|
struct connectdata *conn,
|
||||||
|
ssize_t *nread,
|
||||||
|
bool *readmore);
|
||||||
|
|
||||||
|
|
||||||
|
/* protocol-specific functions set up to be called by the main engine */
|
||||||
|
CURLcode Curl_rtsp(struct connectdata *conn, bool *done);
|
||||||
|
CURLcode Curl_rtsp_done(struct connectdata *conn, CURLcode, bool premature);
|
||||||
|
CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done);
|
||||||
|
CURLcode Curl_rtsp_disconnect(struct connectdata *conn);
|
||||||
|
|
||||||
|
CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
|
||||||
|
|
||||||
|
#endif /* CURL_DISABLE_RTSP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTSP Connection data
|
||||||
|
*
|
||||||
|
* Currently, only used for tracking incomplete RTP data reads
|
||||||
|
*/
|
||||||
|
struct rtsp_conn {
|
||||||
|
char *rtp_buf;
|
||||||
|
ssize_t rtp_bufsize;
|
||||||
|
int rtp_channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* RTSP unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
struct RTSP {
|
||||||
|
/*
|
||||||
|
* http_wrapper MUST be the first element of this structure for the wrap
|
||||||
|
* logic to work. In this way, we get a cheap polymorphism because
|
||||||
|
* &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
|
||||||
|
*
|
||||||
|
* HTTP functions can safely treat this as an HTTP struct, but RTSP aware
|
||||||
|
* functions can also index into the later elements.
|
||||||
|
*/
|
||||||
|
struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */
|
||||||
|
|
||||||
|
long CSeq_sent; /* CSeq of this request */
|
||||||
|
long CSeq_recv; /* CSeq received */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __RTSP_H_ */
|
||||||
17
lib/sendf.c
17
lib/sendf.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
#include "sslgen.h"
|
#include "sslgen.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "multiif.h"
|
#include "multiif.h"
|
||||||
|
#include "rtsp.h"
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
@@ -209,7 +210,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
|
|||||||
write_len = strlen(s);
|
write_len = strlen(s);
|
||||||
sptr = s;
|
sptr = s;
|
||||||
|
|
||||||
while(1) {
|
for(;;) {
|
||||||
/* Write the buffer to the socket */
|
/* Write the buffer to the socket */
|
||||||
res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
|
res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
|
||||||
|
|
||||||
@@ -342,8 +343,8 @@ static CURLcode pausewrite(struct SessionHandle *data,
|
|||||||
/* mark the connection as RECV paused */
|
/* mark the connection as RECV paused */
|
||||||
k->keepon |= KEEP_RECV_PAUSE;
|
k->keepon |= KEEP_RECV_PAUSE;
|
||||||
|
|
||||||
DEBUGF(infof(data, "Pausing with %d bytes in buffer for type %02x\n",
|
DEBUGF(infof(data, "Pausing with %zu bytes in buffer for type %02x\n",
|
||||||
(int)len, type));
|
len, type));
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
@@ -425,7 +426,7 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
|||||||
return pausewrite(data, type, ptr, len);
|
return pausewrite(data, type, ptr, len);
|
||||||
|
|
||||||
if(wrote != len) {
|
if(wrote != len) {
|
||||||
failf(data, "Failed writing body (%d != %d)", (int)wrote, (int)len);
|
failf(data, "Failed writing body (%zu != %zu)", wrote, len);
|
||||||
return CURLE_WRITE_ERROR;
|
return CURLE_WRITE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,7 +511,8 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
|||||||
|
|
||||||
/* If session can pipeline, check connection buffer */
|
/* If session can pipeline, check connection buffer */
|
||||||
if(pipelining) {
|
if(pipelining) {
|
||||||
size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos, sizerequested);
|
size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos,
|
||||||
|
sizerequested);
|
||||||
|
|
||||||
/* Copy from our master buffer first if we have some unread data there*/
|
/* Copy from our master buffer first if we have some unread data there*/
|
||||||
if(bytestocopy > 0) {
|
if(bytestocopy > 0) {
|
||||||
@@ -527,7 +529,8 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
|||||||
buffertofill = conn->master_buffer;
|
buffertofill = conn->master_buffer;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bytesfromsocket = CURLMIN((long)sizerequested, conn->data->set.buffer_size ?
|
bytesfromsocket = CURLMIN((long)sizerequested,
|
||||||
|
conn->data->set.buffer_size ?
|
||||||
conn->data->set.buffer_size : BUFSIZE);
|
conn->data->set.buffer_size : BUFSIZE);
|
||||||
buffertofill = buf;
|
buffertofill = buf;
|
||||||
}
|
}
|
||||||
|
|||||||
15
lib/sendf.h
15
lib/sendf.h
@@ -1,5 +1,5 @@
|
|||||||
#ifndef __SENDF_H
|
#ifndef HEADER_CURL_SENDF_H
|
||||||
#define __SENDF_H
|
#define HEADER_CURL_SENDF_H
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* _ _ ____ _
|
* _ _ ____ _
|
||||||
* Project ___| | | | _ \| |
|
* Project ___| | | | _ \| |
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -48,16 +48,13 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...);
|
|||||||
|
|
||||||
#define failf Curl_failf
|
#define failf Curl_failf
|
||||||
|
|
||||||
#define CLIENTWRITE_BODY 1
|
#define CLIENTWRITE_BODY (1<<0)
|
||||||
#define CLIENTWRITE_HEADER 2
|
#define CLIENTWRITE_HEADER (1<<1)
|
||||||
#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
|
#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
|
||||||
|
|
||||||
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
|
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
|
||||||
void Curl_read_rewind(struct connectdata *conn,
|
|
||||||
size_t extraBytesRead);
|
|
||||||
|
|
||||||
/* internal read-function, does plain socket only */
|
/* internal read-function, does plain socket only */
|
||||||
int Curl_read_plain(curl_socket_t sockfd,
|
int Curl_read_plain(curl_socket_t sockfd,
|
||||||
char *buf,
|
char *buf,
|
||||||
@@ -86,4 +83,4 @@ int Curl_debug(struct SessionHandle *handle, curl_infotype type,
|
|||||||
struct connectdata *conn);
|
struct connectdata *conn);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __SENDF_H */
|
#endif /* HEADER_CURL_SENDF_H */
|
||||||
|
|||||||
96
lib/setup.h
96
lib/setup.h
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -169,6 +169,15 @@
|
|||||||
# define CURL_DISABLE_TELNET
|
# define CURL_DISABLE_TELNET
|
||||||
# define CURL_DISABLE_DICT
|
# define CURL_DISABLE_DICT
|
||||||
# define CURL_DISABLE_FILE
|
# define CURL_DISABLE_FILE
|
||||||
|
# define CURL_DISABLE_RTSP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When http is disabled rtsp is not supported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
|
||||||
|
# define CURL_DISABLE_RTSP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
@@ -326,7 +335,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SIZEOF_OFF_T
|
#ifndef SIZEOF_OFF_T
|
||||||
# if defined(__VMS) && (defined(__alpha) || defined(__ia64))
|
# if defined(__VMS) && !defined(__VAX)
|
||||||
# if defined(_LARGEFILE)
|
# if defined(_LARGEFILE)
|
||||||
# define SIZEOF_OFF_T 8
|
# define SIZEOF_OFF_T 8
|
||||||
# endif
|
# endif
|
||||||
@@ -398,23 +407,68 @@
|
|||||||
|
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
|
/*
|
||||||
!defined(__LCC__) /* lcc-win32 doesn't have _beginthreadex() */
|
* msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
|
||||||
#ifdef ENABLE_IPV6
|
* defined in ws2tcpip.h as well as to provide IPv6 support.
|
||||||
#define USE_THREADING_GETADDRINFO
|
*/
|
||||||
#else
|
|
||||||
#define USE_THREADING_GETHOSTBYNAME /* Cygwin uses alarm() function */
|
#if defined(_MSC_VER) && !defined(__POCC__)
|
||||||
|
# if !defined(HAVE_WS2TCPIP_H) || \
|
||||||
|
((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
|
||||||
|
# undef HAVE_GETADDRINFO_THREADSAFE
|
||||||
|
# undef HAVE_FREEADDRINFO
|
||||||
|
# undef HAVE_GETADDRINFO
|
||||||
|
# undef HAVE_GETNAMEINFO
|
||||||
|
# undef ENABLE_IPV6
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where
|
/* ---------------------------------------------------------------- */
|
||||||
_beginthreadex() is not available */
|
/* resolver specialty compile-time defines */
|
||||||
#if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES)
|
/* CURLRES_* defines to use in the host*.c sources */
|
||||||
#undef USE_THREADING_GETADDRINFO
|
/* ---------------------------------------------------------------- */
|
||||||
#undef USE_THREADING_GETHOSTBYNAME
|
|
||||||
#define CURL_NO__BEGINTHREADEX
|
/*
|
||||||
|
* lcc-win32 doesn't have _beginthreadex(), lacks threads support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__LCC__) && defined(WIN32)
|
||||||
|
# undef USE_THREADS_POSIX
|
||||||
|
# undef USE_THREADS_WIN32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MSVC threads support requires a multi-threaded runtime library.
|
||||||
|
* _beginthreadex() is not available in single-threaded ones.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT)
|
||||||
|
# undef USE_THREADS_POSIX
|
||||||
|
# undef USE_THREADS_WIN32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutually exclusive CURLRES_* definitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
# define CURLRES_ASYNCH
|
||||||
|
# define CURLRES_ARES
|
||||||
|
#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
||||||
|
# define CURLRES_ASYNCH
|
||||||
|
# define CURLRES_THREADED
|
||||||
|
#else
|
||||||
|
# define CURLRES_SYNCH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
# define CURLRES_IPV6
|
||||||
|
#else
|
||||||
|
# define CURLRES_IPV4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When using WINSOCK, TELNET protocol requires WINSOCK2 API.
|
* When using WINSOCK, TELNET protocol requires WINSOCK2 API.
|
||||||
*/
|
*/
|
||||||
@@ -435,20 +489,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
|
|
||||||
* defined in ws2tcpip.h as well as to provide IPv6 support.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__POCC__)
|
|
||||||
# if !defined(HAVE_WS2TCPIP_H) || ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
|
|
||||||
# undef HAVE_FREEADDRINFO
|
|
||||||
# undef HAVE_GETADDRINFO
|
|
||||||
# undef HAVE_GETNAMEINFO
|
|
||||||
# undef ENABLE_IPV6
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intentionally fail to build when using msvc 6.0 without PSDK installed.
|
* Intentionally fail to build when using msvc 6.0 without PSDK installed.
|
||||||
* The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
|
* The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ typedef int sig_atomic_t;
|
|||||||
* Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid()
|
* Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(VMS) && \
|
#if defined(__VMS) && \
|
||||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||||
#define getpwuid __32_getpwuid
|
#define getpwuid __32_getpwuid
|
||||||
#endif
|
#endif
|
||||||
@@ -432,7 +432,7 @@ typedef int sig_atomic_t;
|
|||||||
* Macro argv_item_t hides platform details to code using it.
|
* Macro argv_item_t hides platform details to code using it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#define argv_item_t __char_ptr32
|
#define argv_item_t __char_ptr32
|
||||||
#else
|
#else
|
||||||
#define argv_item_t char *
|
#define argv_item_t char *
|
||||||
|
|||||||
992
lib/smtp.c
Normal file
992
lib/smtp.c
Normal file
@@ -0,0 +1,992 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2010, 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.
|
||||||
|
*
|
||||||
|
* RFC2821 SMTP protocol
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_SMTP
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.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_INET_H
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UTSNAME_H
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NETDB_H
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __VMS
|
||||||
|
#include <in.h>
|
||||||
|
#include <inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
|
||||||
|
#undef in_addr_t
|
||||||
|
#define in_addr_t unsigned long
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "urldata.h"
|
||||||
|
#include "sendf.h"
|
||||||
|
#include "easyif.h" /* for Curl_convert_... prototypes */
|
||||||
|
|
||||||
|
#include "if2ip.h"
|
||||||
|
#include "hostip.h"
|
||||||
|
#include "progress.h"
|
||||||
|
#include "transfer.h"
|
||||||
|
#include "escape.h"
|
||||||
|
#include "http.h" /* for HTTP proxy tunnel stuff */
|
||||||
|
#include "socks.h"
|
||||||
|
#include "smtp.h"
|
||||||
|
|
||||||
|
#include "strtoofft.h"
|
||||||
|
#include "strequal.h"
|
||||||
|
#include "sslgen.h"
|
||||||
|
#include "connect.h"
|
||||||
|
#include "strerror.h"
|
||||||
|
#include "select.h"
|
||||||
|
#include "multiif.h"
|
||||||
|
#include "url.h"
|
||||||
|
#include "rawstr.h"
|
||||||
|
#include "strtoofft.h"
|
||||||
|
|
||||||
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "curl_memory.h"
|
||||||
|
/* The last #include file should be: */
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
/* Local API functions */
|
||||||
|
static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode smtp_do(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode smtp_done(struct connectdata *conn,
|
||||||
|
CURLcode, bool premature);
|
||||||
|
static CURLcode smtp_connect(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode smtp_disconnect(struct connectdata *conn);
|
||||||
|
static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
|
||||||
|
static int smtp_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
static CURLcode smtp_doing(struct connectdata *conn,
|
||||||
|
bool *dophase_done);
|
||||||
|
static CURLcode smtp_setup_connection(struct connectdata * conn);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMTP protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct Curl_handler Curl_handler_smtp = {
|
||||||
|
"SMTP", /* scheme */
|
||||||
|
smtp_setup_connection, /* setup_connection */
|
||||||
|
smtp_do, /* do_it */
|
||||||
|
smtp_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
smtp_connect, /* connect_it */
|
||||||
|
smtp_multi_statemach, /* connecting */
|
||||||
|
smtp_doing, /* doing */
|
||||||
|
smtp_getsock, /* proto_getsock */
|
||||||
|
smtp_getsock, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
smtp_disconnect, /* disconnect */
|
||||||
|
PORT_SMTP, /* defport */
|
||||||
|
PROT_SMTP /* protocol */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_SSL
|
||||||
|
/*
|
||||||
|
* SMTPS protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct Curl_handler Curl_handler_smtps = {
|
||||||
|
"SMTPS", /* scheme */
|
||||||
|
smtp_setup_connection, /* setup_connection */
|
||||||
|
smtp_do, /* do_it */
|
||||||
|
smtp_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
smtp_connect, /* connect_it */
|
||||||
|
smtp_multi_statemach, /* connecting */
|
||||||
|
smtp_doing, /* doing */
|
||||||
|
smtp_getsock, /* proto_getsock */
|
||||||
|
smtp_getsock, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
smtp_disconnect, /* disconnect */
|
||||||
|
PORT_SMTPS, /* defport */
|
||||||
|
PROT_SMTP | PROT_SMTPS | PROT_SSL /* protocol */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_HTTP
|
||||||
|
/*
|
||||||
|
* HTTP-proxyed SMTP protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct Curl_handler Curl_handler_smtp_proxy = {
|
||||||
|
"SMTP", /* scheme */
|
||||||
|
ZERO_NULL, /* setup_connection */
|
||||||
|
Curl_http, /* do_it */
|
||||||
|
Curl_http_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
ZERO_NULL, /* connect_it */
|
||||||
|
ZERO_NULL, /* connecting */
|
||||||
|
ZERO_NULL, /* doing */
|
||||||
|
ZERO_NULL, /* proto_getsock */
|
||||||
|
ZERO_NULL, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
ZERO_NULL, /* disconnect */
|
||||||
|
PORT_SMTP, /* defport */
|
||||||
|
PROT_HTTP /* protocol */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_SSL
|
||||||
|
/*
|
||||||
|
* HTTP-proxyed SMTPS protocol handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct Curl_handler Curl_handler_smtps_proxy = {
|
||||||
|
"SMTPS", /* scheme */
|
||||||
|
ZERO_NULL, /* setup_connection */
|
||||||
|
Curl_http, /* do_it */
|
||||||
|
Curl_http_done, /* done */
|
||||||
|
ZERO_NULL, /* do_more */
|
||||||
|
ZERO_NULL, /* connect_it */
|
||||||
|
ZERO_NULL, /* connecting */
|
||||||
|
ZERO_NULL, /* doing */
|
||||||
|
ZERO_NULL, /* proto_getsock */
|
||||||
|
ZERO_NULL, /* doing_getsock */
|
||||||
|
ZERO_NULL, /* perform_getsock */
|
||||||
|
ZERO_NULL, /* disconnect */
|
||||||
|
PORT_SMTPS, /* defport */
|
||||||
|
PROT_HTTP /* protocol */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* fucntion that checks for an ending smtp status code at the start of the
|
||||||
|
given string */
|
||||||
|
static int smtp_endofresp(struct pingpong *pp, int *resp)
|
||||||
|
{
|
||||||
|
char *line = pp->linestart_resp;
|
||||||
|
size_t len = pp->nread_resp;
|
||||||
|
|
||||||
|
if( (len >= 4) && (' ' == line[3]) &&
|
||||||
|
ISDIGIT(line[0]) && ISDIGIT(line[1]) && ISDIGIT(line[2])) {
|
||||||
|
*resp=atoi(line);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE; /* nothing for us */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the ONLY way to change SMTP state! */
|
||||||
|
static void state(struct connectdata *conn,
|
||||||
|
smtpstate newstate)
|
||||||
|
{
|
||||||
|
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||||
|
/* for debug purposes */
|
||||||
|
static const char * const names[]={
|
||||||
|
"STOP",
|
||||||
|
"SERVERGREET",
|
||||||
|
"EHLO",
|
||||||
|
"STARTTLS",
|
||||||
|
"MAIL",
|
||||||
|
"RCPT",
|
||||||
|
"DATA",
|
||||||
|
"QUIT",
|
||||||
|
/* LAST */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||||
|
if(smtpc->state != newstate)
|
||||||
|
infof(conn->data, "SMTP %p state change from %s to %s\n",
|
||||||
|
smtpc, names[smtpc->state], names[newstate]);
|
||||||
|
#endif
|
||||||
|
smtpc->state = newstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode smtp_state_ehlo(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
|
||||||
|
/* send EHLO */
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "EHLO %s", smtpc->domain);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, SMTP_EHLO);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the SMTP "protocol connect" and "doing" phases only */
|
||||||
|
static int smtp_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for STARTTLS responses */
|
||||||
|
static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
|
||||||
|
int smtpcode,
|
||||||
|
smtpstate instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(smtpcode != 'O') {
|
||||||
|
failf(data, "STARTTLS denied. %c", smtpcode);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Curl_ssl_connect is BLOCKING */
|
||||||
|
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
conn->protocol |= PROT_SMTPS;
|
||||||
|
result = smtp_state_ehlo(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for EHLO responses */
|
||||||
|
static CURLcode smtp_state_ehlo_resp(struct connectdata *conn,
|
||||||
|
int smtpcode,
|
||||||
|
smtpstate instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(smtpcode/100 != 2) {
|
||||||
|
failf(data, "Access denied: %d", smtpcode);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end the connect phase */
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start the DO phase */
|
||||||
|
static CURLcode smtp_mail(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
/* send MAIL */
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s",
|
||||||
|
data->set.str[STRING_MAIL_FROM]);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, SMTP_MAIL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for MAIL responses */
|
||||||
|
static CURLcode smtp_state_mail_resp(struct connectdata *conn,
|
||||||
|
int smtpcode,
|
||||||
|
smtpstate instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(smtpcode/100 != 2) {
|
||||||
|
failf(data, "Access denied: %d", smtpcode);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* send RCPT TO */
|
||||||
|
struct curl_slist *rcpt;
|
||||||
|
char *buffer = NULL;
|
||||||
|
|
||||||
|
for(rcpt = data->set.mail_rcpt; rcpt; rcpt=rcpt->next) {
|
||||||
|
char *add = aprintf("%s%s%s", buffer?buffer:"", buffer?", ":"",
|
||||||
|
rcpt->data);
|
||||||
|
if(!add) {
|
||||||
|
free(buffer);
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
buffer = add;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", buffer);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, SMTP_RCPT);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for RCPT responses */
|
||||||
|
static CURLcode smtp_state_rcpt_resp(struct connectdata *conn,
|
||||||
|
int smtpcode,
|
||||||
|
smtpstate instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(smtpcode/100 != 2) {
|
||||||
|
failf(data, "Access denied: %d", smtpcode);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* send DATA */
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "DATA", "");
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
state(conn, SMTP_DATA);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the DATA response */
|
||||||
|
static CURLcode smtp_state_data_resp(struct connectdata *conn,
|
||||||
|
int smtpcode,
|
||||||
|
smtpstate instate)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *smtp = data->state.proto.smtp;
|
||||||
|
|
||||||
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
|
if(smtpcode != 354) {
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
return CURLE_RECV_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SMTP upload */
|
||||||
|
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
|
||||||
|
FIRSTSOCKET, smtp->bytecountp);
|
||||||
|
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode smtp_statemach_act(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
int smtpcode;
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
struct pingpong *pp = &smtpc->pp;
|
||||||
|
size_t nread = 0;
|
||||||
|
|
||||||
|
if(pp->sendleft)
|
||||||
|
/* we have a piece of a command still left to send */
|
||||||
|
return Curl_pp_flushsend(pp);
|
||||||
|
|
||||||
|
/* we read a piece of response */
|
||||||
|
result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(smtpcode) {
|
||||||
|
/* we have now received a full SMTP server response */
|
||||||
|
switch(smtpc->state) {
|
||||||
|
case SMTP_SERVERGREET:
|
||||||
|
if(smtpcode/100 != 2) {
|
||||||
|
failf(data, "Got unexpected smtp-server response: %d", smtpcode);
|
||||||
|
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
|
||||||
|
/* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
|
||||||
|
to TLS connection now */
|
||||||
|
result = Curl_pp_sendf(&smtpc->pp, "STARTTLS", NULL);
|
||||||
|
state(conn, SMTP_STARTTLS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = smtp_state_ehlo(conn);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_EHLO:
|
||||||
|
result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_MAIL:
|
||||||
|
result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_RCPT:
|
||||||
|
result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_STARTTLS:
|
||||||
|
result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_DATA:
|
||||||
|
result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SMTP_QUIT:
|
||||||
|
/* fallthrough, just stop! */
|
||||||
|
default:
|
||||||
|
/* internal error */
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called repeatedly until done from multi.c */
|
||||||
|
static CURLcode smtp_multi_statemach(struct connectdata *conn,
|
||||||
|
bool *done)
|
||||||
|
{
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
CURLcode result = Curl_pp_multi_statemach(&smtpc->pp);
|
||||||
|
|
||||||
|
*done = (bool)(smtpc->state == SMTP_STOP);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode smtp_easy_statemach(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
struct pingpong *pp = &smtpc->pp;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
while(smtpc->state != SMTP_STOP) {
|
||||||
|
result = Curl_pp_easy_statemach(pp);
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and initialize the struct SMTP for the current SessionHandle. If
|
||||||
|
* need be.
|
||||||
|
*/
|
||||||
|
static CURLcode smtp_init(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *smtp = data->state.proto.smtp;
|
||||||
|
if(!smtp) {
|
||||||
|
smtp = data->state.proto.smtp = calloc(sizeof(struct FTP), 1);
|
||||||
|
if(!smtp)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get some initial data into the smtp struct */
|
||||||
|
smtp->bytecountp = &data->req.bytecount;
|
||||||
|
|
||||||
|
/* No need to duplicate user+password, the connectdata struct won't change
|
||||||
|
during a session, but we re-init them here since on subsequent inits
|
||||||
|
since the conn struct may have changed or been replaced.
|
||||||
|
*/
|
||||||
|
smtp->user = conn->user;
|
||||||
|
smtp->passwd = conn->passwd;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* smtp_connect() should do everything that is to be considered a part of
|
||||||
|
* the connection phase.
|
||||||
|
*
|
||||||
|
* The variable 'done' points to will be TRUE if the protocol-layer connect
|
||||||
|
* phase is done when this function returns, or FALSE is not. When called as
|
||||||
|
* a part of the easy interface, it will always be TRUE.
|
||||||
|
*/
|
||||||
|
static CURLcode smtp_connect(struct connectdata *conn,
|
||||||
|
bool *done) /* see description above */
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
struct pingpong *pp=&smtpc->pp;
|
||||||
|
const char *path = conn->data->state.path;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
*done = FALSE; /* default to not done yet */
|
||||||
|
|
||||||
|
/* If there already is a protocol-specific struct allocated for this
|
||||||
|
sessionhandle, deal with it */
|
||||||
|
Curl_reset_reqproto(conn);
|
||||||
|
|
||||||
|
result = smtp_init(conn);
|
||||||
|
if(CURLE_OK != result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* We always support persistant connections on smtp */
|
||||||
|
conn->bits.close = FALSE;
|
||||||
|
|
||||||
|
pp->response_time = RESP_TIMEOUT; /* set default response time-out */
|
||||||
|
pp->statemach_act = smtp_statemach_act;
|
||||||
|
pp->endofresp = smtp_endofresp;
|
||||||
|
pp->conn = conn;
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
|
||||||
|
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||||||
|
/* for SMTP over HTTP proxy */
|
||||||
|
struct HTTP http_proxy;
|
||||||
|
struct FTP *smtp_save;
|
||||||
|
|
||||||
|
/* BLOCKING */
|
||||||
|
/* We want "seamless" SMTP operations through HTTP proxy tunnel */
|
||||||
|
|
||||||
|
/* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
|
||||||
|
* conn->proto.http; we want SMTP through HTTP and we have to change the
|
||||||
|
* member temporarily for connecting to the HTTP proxy. After
|
||||||
|
* Curl_proxyCONNECT we have to set back the member to the original struct
|
||||||
|
* SMTP pointer
|
||||||
|
*/
|
||||||
|
smtp_save = data->state.proto.smtp;
|
||||||
|
memset(&http_proxy, 0, sizeof(http_proxy));
|
||||||
|
data->state.proto.http = &http_proxy;
|
||||||
|
|
||||||
|
result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
|
||||||
|
conn->host.name, conn->remote_port);
|
||||||
|
|
||||||
|
data->state.proto.smtp = smtp_save;
|
||||||
|
|
||||||
|
if(CURLE_OK != result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
|
||||||
|
|
||||||
|
if(conn->protocol & PROT_SMTPS) {
|
||||||
|
/* BLOCKING */
|
||||||
|
/* SMTPS is simply smtp with SSL for the control channel */
|
||||||
|
/* now, perform the SSL initialization for this socket */
|
||||||
|
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Curl_pp_init(pp); /* init the response reader stuff */
|
||||||
|
|
||||||
|
pp->response_time = RESP_TIMEOUT; /* set default response time-out */
|
||||||
|
pp->statemach_act = smtp_statemach_act;
|
||||||
|
pp->endofresp = smtp_endofresp;
|
||||||
|
pp->conn = conn;
|
||||||
|
|
||||||
|
if(!*path)
|
||||||
|
path = "localhost";
|
||||||
|
|
||||||
|
/* url decode the path and use it as domain with EHLO */
|
||||||
|
smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len);
|
||||||
|
|
||||||
|
/* When we connect, we start in the state where we await the server greeting
|
||||||
|
*/
|
||||||
|
state(conn, SMTP_SERVERGREET);
|
||||||
|
|
||||||
|
if(data->state.used_interface == Curl_if_multi)
|
||||||
|
result = smtp_multi_statemach(conn, done);
|
||||||
|
else {
|
||||||
|
result = smtp_easy_statemach(conn);
|
||||||
|
if(!result)
|
||||||
|
*done = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* smtp_done()
|
||||||
|
*
|
||||||
|
* The DONE function. This does what needs to be done after a single DO has
|
||||||
|
* performed.
|
||||||
|
*
|
||||||
|
* Input argument is already checked for validity.
|
||||||
|
*/
|
||||||
|
static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
|
||||||
|
bool premature)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *smtp = data->state.proto.smtp;
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
ssize_t bytes_written;
|
||||||
|
(void)premature;
|
||||||
|
|
||||||
|
if(!smtp)
|
||||||
|
/* When the easy handle is removed from the multi while libcurl is still
|
||||||
|
* trying to resolve the host name, it seems that the smtp struct is not
|
||||||
|
* yet initialized, but the removal action calls Curl_done() which calls
|
||||||
|
* this function. So we simply return success if no smtp pointer is set.
|
||||||
|
*/
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
|
if(status) {
|
||||||
|
conn->bits.close = TRUE; /* marked for closure */
|
||||||
|
result = status; /* use the already set error code */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* TODO: make this work even when the socket is EWOULDBLOCK in this call! */
|
||||||
|
|
||||||
|
/* write to socket (send away data) */
|
||||||
|
result = Curl_write(conn,
|
||||||
|
conn->writesockfd, /* socket to send to */
|
||||||
|
SMTP_EOB, /* buffer pointer */
|
||||||
|
SMTP_EOB_LEN, /* buffer size */
|
||||||
|
&bytes_written); /* actually sent away */
|
||||||
|
|
||||||
|
/* clear these for next connection */
|
||||||
|
smtp->transfer = FTPTRANSFER_BODY;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* smtp_perform()
|
||||||
|
*
|
||||||
|
* This is the actual DO function for SMTP. Get a file/directory according to
|
||||||
|
* the options previously setup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode smtp_perform(struct connectdata *conn,
|
||||||
|
bool *connected, /* connect status after PASV / PORT */
|
||||||
|
bool *dophase_done)
|
||||||
|
{
|
||||||
|
/* this is SMTP and no proxy */
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
|
||||||
|
DEBUGF(infof(conn->data, "DO phase starts\n"));
|
||||||
|
|
||||||
|
if(conn->data->set.opt_no_body) {
|
||||||
|
/* requested no body means no transfer... */
|
||||||
|
struct FTP *smtp = conn->data->state.proto.smtp;
|
||||||
|
smtp->transfer = FTPTRANSFER_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dophase_done = FALSE; /* not done yet */
|
||||||
|
|
||||||
|
/* start the first command in the DO phase */
|
||||||
|
result = smtp_mail(conn);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* run the state-machine */
|
||||||
|
if(conn->data->state.used_interface == Curl_if_multi)
|
||||||
|
result = smtp_multi_statemach(conn, dophase_done);
|
||||||
|
else {
|
||||||
|
result = smtp_easy_statemach(conn);
|
||||||
|
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||||
|
}
|
||||||
|
*connected = conn->bits.tcpconnect;
|
||||||
|
|
||||||
|
if(*dophase_done)
|
||||||
|
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* smtp_do()
|
||||||
|
*
|
||||||
|
* This function is registered as 'curl_do' function. It decodes the path
|
||||||
|
* parts etc as a wrapper to the actual DO function (smtp_perform).
|
||||||
|
*
|
||||||
|
* The input argument is already checked for validity.
|
||||||
|
*/
|
||||||
|
static CURLcode smtp_do(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
CURLcode retcode = CURLE_OK;
|
||||||
|
|
||||||
|
*done = FALSE; /* default to false */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Since connections can be re-used between SessionHandles, this might be a
|
||||||
|
connection already existing but on a fresh SessionHandle struct so we must
|
||||||
|
make sure we have a good 'struct SMTP' to play with. For new connections,
|
||||||
|
the struct SMTP is allocated and setup in the smtp_connect() function.
|
||||||
|
*/
|
||||||
|
Curl_reset_reqproto(conn);
|
||||||
|
retcode = smtp_init(conn);
|
||||||
|
if(retcode)
|
||||||
|
return retcode;
|
||||||
|
|
||||||
|
retcode = smtp_regular_transfer(conn, done);
|
||||||
|
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* smtp_quit()
|
||||||
|
*
|
||||||
|
* This should be called before calling sclose(). We should then wait for the
|
||||||
|
* response from the server before returning. The calling code should then try
|
||||||
|
* to close the connection.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static CURLcode smtp_quit(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT", NULL);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
state(conn, SMTP_QUIT);
|
||||||
|
|
||||||
|
result = smtp_easy_statemach(conn);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* smtp_disconnect()
|
||||||
|
*
|
||||||
|
* Disconnect from an SMTP server. Cleanup protocol-specific per-connection
|
||||||
|
* resources. BLOCKING.
|
||||||
|
*/
|
||||||
|
static CURLcode smtp_disconnect(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct smtp_conn *smtpc= &conn->proto.smtpc;
|
||||||
|
|
||||||
|
/* We cannot send quit unconditionally. If this connection is stale or
|
||||||
|
bad in any way, sending quit and waiting around here will make the
|
||||||
|
disconnect wait in vain and cause more problems than we need to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The SMTP session may or may not have been allocated/setup at this
|
||||||
|
point! */
|
||||||
|
(void)smtp_quit(conn); /* ignore errors on the LOGOUT */
|
||||||
|
|
||||||
|
Curl_pp_disconnect(&smtpc->pp);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call this when the DO phase has completed */
|
||||||
|
static CURLcode smtp_dophase_done(struct connectdata *conn,
|
||||||
|
bool connected)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct FTP *smtp = conn->data->state.proto.smtp;
|
||||||
|
struct smtp_conn *smtpc= &conn->proto.smtpc;
|
||||||
|
(void)connected;
|
||||||
|
|
||||||
|
if(smtp->transfer != FTPTRANSFER_BODY)
|
||||||
|
/* no data to transfer */
|
||||||
|
result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
|
||||||
|
free(smtpc->domain);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called from multi.c while DOing */
|
||||||
|
static CURLcode smtp_doing(struct connectdata *conn,
|
||||||
|
bool *dophase_done)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
result = smtp_multi_statemach(conn, dophase_done);
|
||||||
|
|
||||||
|
if(*dophase_done) {
|
||||||
|
result = smtp_dophase_done(conn, FALSE /* not connected */);
|
||||||
|
|
||||||
|
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* smtp_regular_transfer()
|
||||||
|
*
|
||||||
|
* The input argument is already checked for validity.
|
||||||
|
*
|
||||||
|
* Performs all commands done before a regular transfer between a local and a
|
||||||
|
* remote host.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
CURLcode smtp_regular_transfer(struct connectdata *conn,
|
||||||
|
bool *dophase_done)
|
||||||
|
{
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
bool connected=FALSE;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
data->req.size = -1; /* make sure this is unknown at this point */
|
||||||
|
|
||||||
|
Curl_pgrsSetUploadCounter(data, 0);
|
||||||
|
Curl_pgrsSetDownloadCounter(data, 0);
|
||||||
|
Curl_pgrsSetUploadSize(data, 0);
|
||||||
|
Curl_pgrsSetDownloadSize(data, 0);
|
||||||
|
|
||||||
|
result = smtp_perform(conn,
|
||||||
|
&connected, /* have we connected after PASV/PORT */
|
||||||
|
dophase_done); /* all commands in the DO-phase done? */
|
||||||
|
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
|
||||||
|
if(!*dophase_done)
|
||||||
|
/* the DO phase has not completed yet */
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
|
result = smtp_dophase_done(conn, connected);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode smtp_setup_connection(struct connectdata * conn)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
|
||||||
|
/* Unless we have asked to tunnel smtp operations through the proxy, we
|
||||||
|
switch and use HTTP operations only */
|
||||||
|
#ifndef CURL_DISABLE_HTTP
|
||||||
|
if(conn->handler == &Curl_handler_smtp)
|
||||||
|
conn->handler = &Curl_handler_smtp_proxy;
|
||||||
|
else {
|
||||||
|
#ifdef USE_SSL
|
||||||
|
conn->handler = &Curl_handler_smtps_proxy;
|
||||||
|
#else
|
||||||
|
failf(data, "SMTPS not supported!");
|
||||||
|
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We explicitly mark this connection as persistent here as we're doing
|
||||||
|
* SMTP over HTTP and thus we accidentally avoid setting this value
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
conn->bits.close = FALSE;
|
||||||
|
#else
|
||||||
|
failf(data, "SMTP over http proxy requires HTTP support built-in!");
|
||||||
|
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
data->state.path++; /* don't include the initial slash */
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_smtp_escape_eob(struct connectdata *conn, int nread)
|
||||||
|
{
|
||||||
|
/* When sending SMTP payload, we must detect CRLF.CRLF sequences in
|
||||||
|
* the data and make sure it is sent as CRLF..CRLF instead, as
|
||||||
|
* otherwise it will wrongly be detected as end of data by the server.
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
int si;
|
||||||
|
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
if(data->state.scratch == NULL)
|
||||||
|
data->state.scratch = malloc(2*BUFSIZE);
|
||||||
|
if(data->state.scratch == NULL) {
|
||||||
|
failf (data, "Failed to alloc scratch buffer!");
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
/* This loop can be improved by some kind of Boyer-Moore style of
|
||||||
|
approach but that is saved for later... */
|
||||||
|
for(i = 0, si = 0; i < nread; i++, si++) {
|
||||||
|
int left = nread - i;
|
||||||
|
|
||||||
|
if(left>= (SMTP_EOB_LEN-smtpc->eob)) {
|
||||||
|
if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
|
||||||
|
SMTP_EOB_LEN-smtpc->eob)) {
|
||||||
|
/* It matched, copy the replacement data to the target buffer
|
||||||
|
instead. Note that the replacement does not contain the
|
||||||
|
trailing CRLF but we instead continue to match on that one
|
||||||
|
to deal with repeated sequences. Like CRLF.CRLF.CRLF etc
|
||||||
|
*/
|
||||||
|
memcpy(&data->state.scratch[si], SMTP_EOB_REPL,
|
||||||
|
SMTP_EOB_REPL_LEN);
|
||||||
|
si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments
|
||||||
|
it */
|
||||||
|
i+=SMTP_EOB_LEN-smtpc->eob-1-2;
|
||||||
|
smtpc->eob = 0; /* start over */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
|
||||||
|
left)) {
|
||||||
|
/* the last piece of the data matches the EOB so we can't send that
|
||||||
|
until we know the rest of it */
|
||||||
|
smtpc->eob += left;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->state.scratch[si] = data->req.upload_fromhere[i];
|
||||||
|
} /* for() */
|
||||||
|
|
||||||
|
if(si != nread) {
|
||||||
|
/* only use the new buffer if we replaced something */
|
||||||
|
nread = si;
|
||||||
|
|
||||||
|
/* upload from the new (replaced) buffer instead */
|
||||||
|
data->req.upload_fromhere = data->state.scratch;
|
||||||
|
|
||||||
|
/* set the new amount too */
|
||||||
|
data->req.upload_present = nread;
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CURL_DISABLE_SMTP */
|
||||||
67
lib/smtp.h
Normal file
67
lib/smtp.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef __SMTP_H
|
||||||
|
#define __SMTP_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, 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 "pingpong.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* SMTP unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
typedef enum {
|
||||||
|
SMTP_STOP, /* do nothing state, stops the state machine */
|
||||||
|
SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
|
||||||
|
a connect */
|
||||||
|
SMTP_EHLO,
|
||||||
|
SMTP_STARTTLS,
|
||||||
|
SMTP_MAIL, /* MAIL FROM */
|
||||||
|
SMTP_RCPT, /* RCPT TO */
|
||||||
|
SMTP_DATA,
|
||||||
|
SMTP_QUIT,
|
||||||
|
SMTP_LAST /* never used */
|
||||||
|
} smtpstate;
|
||||||
|
|
||||||
|
/* smtp_conn is used for struct connection-oriented data in the connectdata
|
||||||
|
struct */
|
||||||
|
struct smtp_conn {
|
||||||
|
struct pingpong pp;
|
||||||
|
char *domain; /* what to send in the EHLO */
|
||||||
|
int eob; /* number of bytes of the EOB (End Of Body) that has been
|
||||||
|
received thus far */
|
||||||
|
smtpstate state; /* always use smtp.c:state() to change state! */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct Curl_handler Curl_handler_smtp;
|
||||||
|
extern const struct Curl_handler Curl_handler_smtps;
|
||||||
|
|
||||||
|
/* this is the 5-bytes End-Of-Body marker for SMTP */
|
||||||
|
#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
|
||||||
|
#define SMTP_EOB_LEN 5
|
||||||
|
|
||||||
|
/* if found in data, replace it with this string instead */
|
||||||
|
#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
|
||||||
|
#define SMTP_EOB_REPL_LEN 4
|
||||||
|
|
||||||
|
CURLcode Curl_smtp_escape_eob(struct connectdata *conn, int nread);
|
||||||
|
|
||||||
|
#endif /* __SMTP_H */
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -72,7 +72,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
|
|||||||
struct timeval tvnow;
|
struct timeval tvnow;
|
||||||
long conntime;
|
long conntime;
|
||||||
*n = 0;
|
*n = 0;
|
||||||
do {
|
for(;;) {
|
||||||
tvnow = Curl_tvnow();
|
tvnow = Curl_tvnow();
|
||||||
/* calculating how long connection is establishing */
|
/* calculating how long connection is establishing */
|
||||||
conntime = Curl_tvdiff(tvnow, conn->created);
|
conntime = Curl_tvdiff(tvnow, conn->created);
|
||||||
@@ -104,7 +104,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
|
|||||||
buffersize -= nread;
|
buffersize -= nread;
|
||||||
buf += nread;
|
buf += nread;
|
||||||
allread += nread;
|
allread += nread;
|
||||||
} while(1);
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
|
|||||||
if(!socks5_resolve_local && hostname_len > 255)
|
if(!socks5_resolve_local && hostname_len > 255)
|
||||||
{
|
{
|
||||||
infof(conn->data,"SOCKS5: server resolving disabled for hostnames of "
|
infof(conn->data,"SOCKS5: server resolving disabled for hostnames of "
|
||||||
"length > 255 [actual len=%d]\n", hostname_len);
|
"length > 255 [actual len=%zu]\n", hostname_len);
|
||||||
socks5_resolve_local = TRUE;
|
socks5_resolve_local = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
|
|||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "curl_memory.h"
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "curl_memory.h"
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -54,7 +54,7 @@ CURLcode Curl_speedcheck(struct SessionHandle *data,
|
|||||||
/* we have been this slow for long enough, now die */
|
/* we have been this slow for long enough, now die */
|
||||||
failf(data,
|
failf(data,
|
||||||
"Operation too slow. "
|
"Operation too slow. "
|
||||||
"Less than %d bytes/sec transfered the last %d seconds",
|
"Less than %ld bytes/sec transfered the last %ld seconds",
|
||||||
data->set.low_speed_limit,
|
data->set.low_speed_limit,
|
||||||
data->set.low_speed_time);
|
data->set.low_speed_time);
|
||||||
return CURLE_OPERATION_TIMEDOUT;
|
return CURLE_OPERATION_TIMEDOUT;
|
||||||
|
|||||||
78
lib/ssh.c
78
lib/ssh.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
#ifdef HAVE_NETDB_H
|
#ifdef HAVE_NETDB_H
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef VMS
|
#ifdef __VMS
|
||||||
#include <in.h>
|
#include <in.h>
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -264,9 +264,37 @@ static CURLcode sftp_libssh2_error_to_CURLE(int err)
|
|||||||
|
|
||||||
static CURLcode libssh2_session_error_to_CURLE(int err)
|
static CURLcode libssh2_session_error_to_CURLE(int err)
|
||||||
{
|
{
|
||||||
if(err == LIBSSH2_ERROR_ALLOC)
|
switch (err) {
|
||||||
|
/* Ordered by order of appearance in libssh2.h */
|
||||||
|
case LIBSSH2_ERROR_NONE:
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_SOCKET_NONE:
|
||||||
|
return CURLE_COULDNT_CONNECT;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_ALLOC:
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_SOCKET_SEND:
|
||||||
|
return CURLE_SEND_ERROR;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_HOSTKEY_INIT:
|
||||||
|
case LIBSSH2_ERROR_HOSTKEY_SIGN:
|
||||||
|
case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
|
||||||
|
case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
|
||||||
|
return CURLE_PEER_FAILED_VERIFICATION;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_PASSWORD_EXPIRED:
|
||||||
|
return CURLE_LOGIN_DENIED;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_SOCKET_TIMEOUT:
|
||||||
|
case LIBSSH2_ERROR_TIMEOUT:
|
||||||
|
return CURLE_OPERATION_TIMEDOUT;
|
||||||
|
|
||||||
|
case LIBSSH2_ERROR_EAGAIN:
|
||||||
|
return CURLE_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
|
/* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
|
||||||
error code, and possibly add a few new SSH-related one. We must however
|
error code, and possibly add a few new SSH-related one. We must however
|
||||||
not return or even depend on libssh2 errors in the public libcurl API */
|
not return or even depend on libssh2 errors in the public libcurl API */
|
||||||
@@ -459,10 +487,10 @@ static int sshkeycallback(CURL *easy,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ssh_statemach_act() runs the SSH statemachine "one round" and returns. The
|
* ssh_statemach_act() runs the SSH state machine as far as it can without
|
||||||
* data the pointer 'block' points to will be set to TRUE if the libssh2
|
* blocking and without reaching the end. The data the pointer 'block' points
|
||||||
* function returns LIBSSH2_ERROR_EAGAIN meaning it wants to be called again
|
* to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
|
||||||
* when the socket is ready
|
* meaning it wants to be called again when the socket is ready
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||||
@@ -481,6 +509,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
int seekerr = CURL_SEEKFUNC_OK;
|
int seekerr = CURL_SEEKFUNC_OK;
|
||||||
*block = 0; /* we're not blocking by default */
|
*block = 0; /* we're not blocking by default */
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
switch(sshc->state) {
|
switch(sshc->state) {
|
||||||
case SSH_S_STARTUP:
|
case SSH_S_STARTUP:
|
||||||
sshc->secondCreateDirs = 0;
|
sshc->secondCreateDirs = 0;
|
||||||
@@ -935,7 +965,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
err = libssh2_sftp_last_error(sshc->sftp_session);
|
err = libssh2_sftp_last_error(sshc->sftp_session);
|
||||||
result = sftp_libssh2_error_to_CURLE(err);
|
result = sftp_libssh2_error_to_CURLE(err);
|
||||||
sshc->actualcode = result?result:CURLE_SSH;
|
sshc->actualcode = result?result:CURLE_SSH;
|
||||||
DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, result));
|
DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
|
||||||
|
err, (int)result));
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_STOP);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1429,9 +1460,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
sshc->actualcode = err>= LIBSSH2_FX_OK?
|
sshc->actualcode = err>= LIBSSH2_FX_OK?
|
||||||
sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
|
sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
|
||||||
if(!sshc->actualcode) {
|
if(!sshc->actualcode) {
|
||||||
/* Sometimes, for some reason libssh2_sftp_last_error() returns zero
|
/* Sometimes, for some reason libssh2_sftp_last_error() returns
|
||||||
even though libssh2_sftp_open() failed previously! We need to
|
zero even though libssh2_sftp_open() failed previously! We need
|
||||||
work around that! */
|
to work around that! */
|
||||||
sshc->actualcode = CURLE_SSH;
|
sshc->actualcode = CURLE_SSH;
|
||||||
err=-1;
|
err=-1;
|
||||||
}
|
}
|
||||||
@@ -1442,7 +1473,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have restart point then we need to seek to the correct position. */
|
/* If we have restart point then we need to seek to the correct
|
||||||
|
position. */
|
||||||
if(data->state.resume_from > 0) {
|
if(data->state.resume_from > 0) {
|
||||||
/* Let's read off the proper amount of bytes from the input. */
|
/* Let's read off the proper amount of bytes from the input. */
|
||||||
if(conn->seek_func) {
|
if(conn->seek_func) {
|
||||||
@@ -1508,8 +1540,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
sshc->actualcode = result;
|
sshc->actualcode = result;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* store this original bitmask setup to use later on if we can't figure
|
/* store this original bitmask setup to use later on if we can't
|
||||||
out a "real" bitmask */
|
figure out a "real" bitmask */
|
||||||
sshc->orig_waitfor = data->req.keepon;
|
sshc->orig_waitfor = data->req.keepon;
|
||||||
|
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_STOP);
|
||||||
@@ -1552,9 +1584,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
if(rc == -1) {
|
if(rc == -1) {
|
||||||
unsigned int sftp_err = 0;
|
unsigned int sftp_err = 0;
|
||||||
/*
|
/*
|
||||||
* abort if failure wasn't that the dir already exists or the
|
* Abort if failure wasn't that the dir already exists or the
|
||||||
* permission was denied (creation might succeed further
|
* permission was denied (creation might succeed further down the
|
||||||
* down the path) - retry on unspecific FAILURE also
|
* path) - retry on unspecific FAILURE also
|
||||||
*/
|
*/
|
||||||
sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
|
sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
|
||||||
if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
|
if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
|
||||||
@@ -1571,8 +1603,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
|
|
||||||
case SSH_SFTP_READDIR_INIT:
|
case SSH_SFTP_READDIR_INIT:
|
||||||
/*
|
/*
|
||||||
* This is a directory that we are trying to get, so produce a
|
* This is a directory that we are trying to get, so produce a directory
|
||||||
* directory listing
|
* listing
|
||||||
*/
|
*/
|
||||||
sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
|
sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
|
||||||
sftp_scp->path);
|
sftp_scp->path);
|
||||||
@@ -1638,8 +1670,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
state(conn, SSH_STOP);
|
state(conn, SSH_STOP);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* since this counts what we send to the client, we include the newline
|
/* since this counts what we send to the client, we include the
|
||||||
in this counter */
|
newline in this counter */
|
||||||
data->req.bytecount += sshc->readdir_len+1;
|
data->req.bytecount += sshc->readdir_len+1;
|
||||||
|
|
||||||
/* output debug output if that is requested */
|
/* output debug output if that is requested */
|
||||||
@@ -2236,6 +2268,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} while(!rc && (sshc->state != SSH_STOP));
|
||||||
|
|
||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
/* we would block, we need to wait for the socket to be ready (in the
|
/* we would block, we need to wait for the socket to be ready (in the
|
||||||
right direction too)! */
|
right direction too)! */
|
||||||
@@ -2458,7 +2492,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
|
|||||||
|
|
||||||
#ifdef CURL_LIBSSH2_DEBUG
|
#ifdef CURL_LIBSSH2_DEBUG
|
||||||
libssh2_trace(ssh->ssh_session, ~0);
|
libssh2_trace(ssh->ssh_session, ~0);
|
||||||
infof(data, "SSH socket: %d\n", sock);
|
infof(data, "SSH socket: %d\n", (int)sock);
|
||||||
#endif /* CURL_LIBSSH2_DEBUG */
|
#endif /* CURL_LIBSSH2_DEBUG */
|
||||||
|
|
||||||
state(conn, SSH_S_STARTUP);
|
state(conn, SSH_S_STARTUP);
|
||||||
|
|||||||
122
lib/ssh.h
122
lib/ssh.h
@@ -23,6 +23,128 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2_H
|
||||||
|
#include <libssh2.h>
|
||||||
|
#include <libssh2_sftp.h>
|
||||||
|
#endif /* HAVE_LIBSSH2_H */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* SSH unique setup
|
||||||
|
***************************************************************************/
|
||||||
|
typedef enum {
|
||||||
|
SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */
|
||||||
|
SSH_STOP = 0, /* do nothing state, stops the state machine */
|
||||||
|
|
||||||
|
SSH_S_STARTUP, /* Session startup, First state in SSH-CONNECT */
|
||||||
|
SSH_HOSTKEY, /* verify hostkey */
|
||||||
|
SSH_AUTHLIST,
|
||||||
|
SSH_AUTH_PKEY_INIT,
|
||||||
|
SSH_AUTH_PKEY,
|
||||||
|
SSH_AUTH_PASS_INIT,
|
||||||
|
SSH_AUTH_PASS,
|
||||||
|
SSH_AUTH_HOST_INIT,
|
||||||
|
SSH_AUTH_HOST,
|
||||||
|
SSH_AUTH_KEY_INIT,
|
||||||
|
SSH_AUTH_KEY,
|
||||||
|
SSH_AUTH_DONE,
|
||||||
|
SSH_SFTP_INIT,
|
||||||
|
SSH_SFTP_REALPATH, /* Last state in SSH-CONNECT */
|
||||||
|
|
||||||
|
SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */
|
||||||
|
SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */
|
||||||
|
SSH_SFTP_QUOTE,
|
||||||
|
SSH_SFTP_NEXT_QUOTE,
|
||||||
|
SSH_SFTP_QUOTE_STAT,
|
||||||
|
SSH_SFTP_QUOTE_SETSTAT,
|
||||||
|
SSH_SFTP_QUOTE_SYMLINK,
|
||||||
|
SSH_SFTP_QUOTE_MKDIR,
|
||||||
|
SSH_SFTP_QUOTE_RENAME,
|
||||||
|
SSH_SFTP_QUOTE_RMDIR,
|
||||||
|
SSH_SFTP_QUOTE_UNLINK,
|
||||||
|
SSH_SFTP_TRANS_INIT,
|
||||||
|
SSH_SFTP_UPLOAD_INIT,
|
||||||
|
SSH_SFTP_CREATE_DIRS_INIT,
|
||||||
|
SSH_SFTP_CREATE_DIRS,
|
||||||
|
SSH_SFTP_CREATE_DIRS_MKDIR,
|
||||||
|
SSH_SFTP_READDIR_INIT,
|
||||||
|
SSH_SFTP_READDIR,
|
||||||
|
SSH_SFTP_READDIR_LINK,
|
||||||
|
SSH_SFTP_READDIR_BOTTOM,
|
||||||
|
SSH_SFTP_READDIR_DONE,
|
||||||
|
SSH_SFTP_DOWNLOAD_INIT,
|
||||||
|
SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */
|
||||||
|
SSH_SFTP_CLOSE, /* Last state in SFTP-DONE */
|
||||||
|
SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */
|
||||||
|
SSH_SCP_TRANS_INIT, /* First state in SCP-DO */
|
||||||
|
SSH_SCP_UPLOAD_INIT,
|
||||||
|
SSH_SCP_DOWNLOAD_INIT,
|
||||||
|
SSH_SCP_DONE,
|
||||||
|
SSH_SCP_SEND_EOF,
|
||||||
|
SSH_SCP_WAIT_EOF,
|
||||||
|
SSH_SCP_WAIT_CLOSE,
|
||||||
|
SSH_SCP_CHANNEL_FREE, /* Last state in SCP-DONE */
|
||||||
|
SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */
|
||||||
|
SSH_SESSION_FREE, /* Last state in SCP/SFTP-DISCONNECT */
|
||||||
|
SSH_QUIT,
|
||||||
|
SSH_LAST /* never used */
|
||||||
|
} sshstate;
|
||||||
|
|
||||||
|
/* this struct is used in the HandleData struct which is part of the
|
||||||
|
SessionHandle, which means this is used on a per-easy handle basis.
|
||||||
|
Everything that is strictly related to a connection is banned from this
|
||||||
|
struct. */
|
||||||
|
struct SSHPROTO {
|
||||||
|
char *path; /* the path we operate on */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ssh_conn is used for struct connection-oriented data in the connectdata
|
||||||
|
struct */
|
||||||
|
struct ssh_conn {
|
||||||
|
const char *authlist; /* List of auth. methods, managed by libssh2 */
|
||||||
|
#ifdef USE_LIBSSH2
|
||||||
|
const char *passphrase; /* pass-phrase to use */
|
||||||
|
char *rsa_pub; /* path name */
|
||||||
|
char *rsa; /* path name */
|
||||||
|
bool authed; /* the connection has been authenticated fine */
|
||||||
|
sshstate state; /* always use ssh.c:state() to change state! */
|
||||||
|
sshstate nextstate; /* the state to goto after stopping */
|
||||||
|
CURLcode actualcode; /* the actual error code */
|
||||||
|
struct curl_slist *quote_item; /* for the quote option */
|
||||||
|
char *quote_path1; /* two generic pointers for the QUOTE stuff */
|
||||||
|
char *quote_path2;
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
|
||||||
|
char *homedir; /* when doing SFTP we figure out home dir in the
|
||||||
|
connect phase */
|
||||||
|
|
||||||
|
/* Here's a set of struct members used by the SFTP_READDIR state */
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
|
||||||
|
char *readdir_filename;
|
||||||
|
char *readdir_longentry;
|
||||||
|
int readdir_len, readdir_totalLen, readdir_currLen;
|
||||||
|
char *readdir_line;
|
||||||
|
char *readdir_linkPath;
|
||||||
|
/* end of READDIR stuff */
|
||||||
|
|
||||||
|
int secondCreateDirs; /* counter use by the code to see if the
|
||||||
|
second attempt has been made to change
|
||||||
|
to/create a directory */
|
||||||
|
char *slash_pos; /* used by the SFTP_CREATE_DIRS state */
|
||||||
|
LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
|
||||||
|
LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
|
||||||
|
LIBSSH2_SFTP *sftp_session; /* SFTP handle */
|
||||||
|
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||||
|
int orig_waitfor; /* default READ/WRITE bits wait for */
|
||||||
|
|
||||||
|
/* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
|
||||||
|
header */
|
||||||
|
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
||||||
|
LIBSSH2_KNOWNHOSTS *kh;
|
||||||
|
#endif
|
||||||
|
#endif /* USE_LIBSSH2 */
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef USE_LIBSSH2
|
#ifdef USE_LIBSSH2
|
||||||
|
|
||||||
#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
|
#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
|
||||||
|
|||||||
48
lib/ssluse.c
48
lib/ssluse.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -483,8 +483,7 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) {
|
if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) {
|
||||||
failf(data, "cannot add certificate to client CA list",
|
failf(data, "cannot add certificate to client CA list");
|
||||||
cert_file);
|
|
||||||
EVP_PKEY_free(pri);
|
EVP_PKEY_free(pri);
|
||||||
X509_free(x509);
|
X509_free(x509);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -595,14 +594,14 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
* the SSL context */
|
* the SSL context */
|
||||||
if(!SSL_CTX_check_private_key(ctx)) {
|
if(!SSL_CTX_check_private_key(ctx)) {
|
||||||
failf(data, "Private key does not match the certificate public key");
|
failf(data, "Private key does not match the certificate public key");
|
||||||
return(0);
|
return 0;
|
||||||
}
|
}
|
||||||
#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
|
#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
|
||||||
/* erase it now */
|
/* erase it now */
|
||||||
memset(global_passwd, 0, sizeof(global_passwd));
|
memset(global_passwd, 0, sizeof(global_passwd));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return(1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns non-zero on failure */
|
/* returns non-zero on failure */
|
||||||
@@ -659,7 +658,7 @@ static char *SSL_strerror(unsigned long error, char *buf, size_t size)
|
|||||||
(void) size;
|
(void) size;
|
||||||
ERR_error_string(error, buf);
|
ERR_error_string(error, buf);
|
||||||
#endif
|
#endif
|
||||||
return (buf);
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* USE_SSLEAY */
|
#endif /* USE_SSLEAY */
|
||||||
@@ -709,7 +708,7 @@ void Curl_ossl_cleanup(void)
|
|||||||
/* EVP_cleanup() removes all ciphers and digests from the table. */
|
/* EVP_cleanup() removes all ciphers and digests from the table. */
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
|
|
||||||
#ifdef HAVE_ENGINE_cleanup
|
#ifdef HAVE_ENGINE_CLEANUP
|
||||||
ENGINE_cleanup();
|
ENGINE_cleanup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -748,11 +747,22 @@ int Curl_ossl_check_cxn(struct connectdata *conn)
|
|||||||
CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
|
CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
|
||||||
{
|
{
|
||||||
#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
|
#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
|
||||||
ENGINE *e = ENGINE_by_id(engine);
|
ENGINE *e;
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x00909000L
|
||||||
|
e = ENGINE_by_id(engine);
|
||||||
|
#else
|
||||||
|
/* avoid memory leak */
|
||||||
|
for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
|
||||||
|
const char *e_id = ENGINE_get_id(e);
|
||||||
|
if(!strcmp(engine, e_id))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!e) {
|
if(!e) {
|
||||||
failf(data, "SSL Engine '%s' not found", engine);
|
failf(data, "SSL Engine '%s' not found", engine);
|
||||||
return (CURLE_SSL_ENGINE_NOTFOUND);
|
return CURLE_SSL_ENGINE_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->state.engine) {
|
if(data->state.engine) {
|
||||||
@@ -766,14 +776,14 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
|
|||||||
ENGINE_free(e);
|
ENGINE_free(e);
|
||||||
failf(data, "Failed to initialise SSL Engine '%s':\n%s",
|
failf(data, "Failed to initialise SSL Engine '%s':\n%s",
|
||||||
engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
|
engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
|
||||||
return (CURLE_SSL_ENGINE_INITFAILED);
|
return CURLE_SSL_ENGINE_INITFAILED;
|
||||||
}
|
}
|
||||||
data->state.engine = e;
|
data->state.engine = e;
|
||||||
return (CURLE_OK);
|
return CURLE_OK;
|
||||||
#else
|
#else
|
||||||
(void)engine;
|
(void)engine;
|
||||||
failf(data, "SSL Engine not supported");
|
failf(data, "SSL Engine not supported");
|
||||||
return (CURLE_SSL_ENGINE_NOTFOUND);
|
return CURLE_SSL_ENGINE_NOTFOUND;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,7 +828,7 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
(void) data;
|
(void) data;
|
||||||
return (list);
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1735,7 +1745,7 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
|
|||||||
* the SO_ERROR is also lost.
|
* the SO_ERROR is also lost.
|
||||||
*/
|
*/
|
||||||
if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
|
if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
|
||||||
failf(data, "Unknown SSL protocol error in connection to %s:%d ",
|
failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
|
||||||
conn->host.name, conn->port);
|
conn->host.name, conn->port);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -2315,7 +2325,15 @@ ossl_connect_step3(struct connectdata *conn,
|
|||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_SSL_GET1_SESSION
|
||||||
|
else {
|
||||||
|
/* Session was incache, so refcount already incremented earlier.
|
||||||
|
* Avoid further increments with each SSL_get1_session() call.
|
||||||
|
* This does not free the session as refcount remains > 0
|
||||||
|
*/
|
||||||
|
SSL_SESSION_free(our_ssl_sessionid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We check certificates to authenticate the server; otherwise we risk
|
* We check certificates to authenticate the server; otherwise we risk
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 2004 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -81,6 +81,9 @@ curl_easy_strerror(CURLcode error)
|
|||||||
case CURLE_REMOTE_ACCESS_DENIED:
|
case CURLE_REMOTE_ACCESS_DENIED:
|
||||||
return "Access denied to remote resource";
|
return "Access denied to remote resource";
|
||||||
|
|
||||||
|
case CURLE_FTP_PRET_FAILED:
|
||||||
|
return "FTP: The server did not accept the PRET command.";
|
||||||
|
|
||||||
case CURLE_FTP_WEIRD_PASS_REPLY:
|
case CURLE_FTP_WEIRD_PASS_REPLY:
|
||||||
return "FTP: unknown PASS reply";
|
return "FTP: unknown PASS reply";
|
||||||
|
|
||||||
@@ -267,6 +270,12 @@ curl_easy_strerror(CURLcode error)
|
|||||||
case CURLE_AGAIN:
|
case CURLE_AGAIN:
|
||||||
return "Socket not ready for send/recv";
|
return "Socket not ready for send/recv";
|
||||||
|
|
||||||
|
case CURLE_RTSP_CSEQ_ERROR:
|
||||||
|
return "RTSP CSeq mismatch or invalid CSeq";
|
||||||
|
|
||||||
|
case CURLE_RTSP_SESSION_ERROR:
|
||||||
|
return "RTSP session error";
|
||||||
|
|
||||||
/* error codes not used by current libcurl */
|
/* error codes not used by current libcurl */
|
||||||
case CURLE_OBSOLETE4:
|
case CURLE_OBSOLETE4:
|
||||||
case CURLE_OBSOLETE10:
|
case CURLE_OBSOLETE10:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -729,7 +729,7 @@ static void printsub(struct SessionHandle *data,
|
|||||||
else if(CURL_TELCMD_OK(i))
|
else if(CURL_TELCMD_OK(i))
|
||||||
infof(data, "%s ", CURL_TELCMD(i));
|
infof(data, "%s ", CURL_TELCMD(i));
|
||||||
else
|
else
|
||||||
infof(data, "%d ", i);
|
infof(data, "%u ", i);
|
||||||
if(CURL_TELOPT_OK(j))
|
if(CURL_TELOPT_OK(j))
|
||||||
infof(data, "%s", CURL_TELOPT(j));
|
infof(data, "%s", CURL_TELOPT(j));
|
||||||
else if(CURL_TELCMD_OK(j))
|
else if(CURL_TELCMD_OK(j))
|
||||||
@@ -1325,7 +1325,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
|
|||||||
switch(waitret) {
|
switch(waitret) {
|
||||||
case WAIT_TIMEOUT:
|
case WAIT_TIMEOUT:
|
||||||
{
|
{
|
||||||
while(1) {
|
for(;;) {
|
||||||
if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
|
if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
|
||||||
keepon = FALSE;
|
keepon = FALSE;
|
||||||
code = CURLE_READ_ERROR;
|
code = CURLE_READ_ERROR;
|
||||||
|
|||||||
685
lib/tftp.c
685
lib/tftp.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
#include "strerror.h"
|
#include "strerror.h"
|
||||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||||
|
#include "multiif.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
#include "rawstr.h"
|
#include "rawstr.h"
|
||||||
|
|
||||||
@@ -103,6 +104,7 @@ typedef enum {
|
|||||||
} tftp_state_t;
|
} tftp_state_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
TFTP_EVENT_NONE = -1,
|
||||||
TFTP_EVENT_INIT = 0,
|
TFTP_EVENT_INIT = 0,
|
||||||
TFTP_EVENT_RRQ = 1,
|
TFTP_EVENT_RRQ = 1,
|
||||||
TFTP_EVENT_WRQ = 2,
|
TFTP_EVENT_WRQ = 2,
|
||||||
@@ -137,20 +139,22 @@ typedef struct tftp_state_data {
|
|||||||
tftp_state_t state;
|
tftp_state_t state;
|
||||||
tftp_mode_t mode;
|
tftp_mode_t mode;
|
||||||
tftp_error_t error;
|
tftp_error_t error;
|
||||||
|
tftp_event_t event;
|
||||||
struct connectdata *conn;
|
struct connectdata *conn;
|
||||||
curl_socket_t sockfd;
|
curl_socket_t sockfd;
|
||||||
int retries;
|
int retries;
|
||||||
time_t retry_time;
|
int retry_time;
|
||||||
time_t retry_max;
|
int retry_max;
|
||||||
time_t start_time;
|
time_t start_time;
|
||||||
time_t max_time;
|
time_t max_time;
|
||||||
|
time_t rx_time;
|
||||||
unsigned short block;
|
unsigned short block;
|
||||||
struct Curl_sockaddr_storage local_addr;
|
struct Curl_sockaddr_storage local_addr;
|
||||||
struct Curl_sockaddr_storage remote_addr;
|
struct Curl_sockaddr_storage remote_addr;
|
||||||
curl_socklen_t remote_addrlen;
|
curl_socklen_t remote_addrlen;
|
||||||
ssize_t rbytes;
|
int rbytes;
|
||||||
size_t sbytes;
|
int sbytes;
|
||||||
size_t blksize;
|
int blksize;
|
||||||
int requested_blksize;
|
int requested_blksize;
|
||||||
tftp_packet_t rpacket;
|
tftp_packet_t rpacket;
|
||||||
tftp_packet_t spacket;
|
tftp_packet_t spacket;
|
||||||
@@ -166,6 +170,11 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done);
|
|||||||
static CURLcode tftp_done(struct connectdata *conn,
|
static CURLcode tftp_done(struct connectdata *conn,
|
||||||
CURLcode, bool premature);
|
CURLcode, bool premature);
|
||||||
static CURLcode tftp_setup_connection(struct connectdata * conn);
|
static CURLcode tftp_setup_connection(struct connectdata * conn);
|
||||||
|
static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
|
||||||
|
static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
|
||||||
|
static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
static CURLcode tftp_translate_code(tftp_error_t error);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -179,17 +188,16 @@ const struct Curl_handler Curl_handler_tftp = {
|
|||||||
tftp_done, /* done */
|
tftp_done, /* done */
|
||||||
ZERO_NULL, /* do_more */
|
ZERO_NULL, /* do_more */
|
||||||
tftp_connect, /* connect_it */
|
tftp_connect, /* connect_it */
|
||||||
ZERO_NULL, /* connecting */
|
tftp_multi_statemach, /* connecting */
|
||||||
ZERO_NULL, /* doing */
|
tftp_doing, /* doing */
|
||||||
ZERO_NULL, /* proto_getsock */
|
tftp_getsock, /* proto_getsock */
|
||||||
ZERO_NULL, /* doing_getsock */
|
tftp_getsock, /* doing_getsock */
|
||||||
ZERO_NULL, /* perform_getsock */
|
ZERO_NULL, /* perform_getsock */
|
||||||
tftp_disconnect, /* disconnect */
|
tftp_disconnect, /* disconnect */
|
||||||
PORT_TFTP, /* defport */
|
PORT_TFTP, /* defport */
|
||||||
PROT_TFTP /* protocol */
|
PROT_TFTP /* protocol */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************
|
/**********************************************************
|
||||||
*
|
*
|
||||||
* tftp_set_timeouts -
|
* tftp_set_timeouts -
|
||||||
@@ -226,14 +234,14 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
|||||||
timeout = maxtime ;
|
timeout = maxtime ;
|
||||||
|
|
||||||
/* Average restart after 5 seconds */
|
/* Average restart after 5 seconds */
|
||||||
state->retry_max = timeout/5;
|
state->retry_max = (int)timeout/5;
|
||||||
|
|
||||||
if(state->retry_max < 1)
|
if(state->retry_max < 1)
|
||||||
/* avoid division by zero below */
|
/* avoid division by zero below */
|
||||||
state->retry_max = 1;
|
state->retry_max = 1;
|
||||||
|
|
||||||
/* Compute the re-start interval to suit the timeout */
|
/* Compute the re-start interval to suit the timeout */
|
||||||
state->retry_time = timeout/state->retry_max;
|
state->retry_time = (int)timeout/state->retry_max;
|
||||||
if(state->retry_time<1)
|
if(state->retry_time<1)
|
||||||
state->retry_time=1;
|
state->retry_time=1;
|
||||||
|
|
||||||
@@ -250,7 +258,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
|||||||
timeout = maxtime/10 ;
|
timeout = maxtime/10 ;
|
||||||
|
|
||||||
/* Average reposting an ACK after 15 seconds */
|
/* Average reposting an ACK after 15 seconds */
|
||||||
state->retry_max = timeout/15;
|
state->retry_max = (int)timeout/15;
|
||||||
}
|
}
|
||||||
/* But bound the total number */
|
/* But bound the total number */
|
||||||
if(state->retry_max<3)
|
if(state->retry_max<3)
|
||||||
@@ -265,10 +273,13 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
|||||||
state->retry_time=1;
|
state->retry_time=1;
|
||||||
|
|
||||||
infof(state->conn->data,
|
infof(state->conn->data,
|
||||||
"set timeouts for state %d; Total %d, retry %d maxtry %d\n",
|
"set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
|
||||||
state->state, (state->max_time-state->start_time),
|
(int)state->state, (long)(state->max_time-state->start_time),
|
||||||
state->retry_time, state->retry_max);
|
state->retry_time, state->retry_max);
|
||||||
|
|
||||||
|
/* init RX time */
|
||||||
|
time(&state->rx_time);
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,9 +363,9 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
|
|||||||
infof(data, "got option=(%s) value=(%s)\n", option, value);
|
infof(data, "got option=(%s) value=(%s)\n", option, value);
|
||||||
|
|
||||||
if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
|
if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
|
||||||
int blksize;
|
long blksize;
|
||||||
|
|
||||||
blksize = (int)strtol( value, NULL, 10 );
|
blksize = strtol( value, NULL, 10 );
|
||||||
|
|
||||||
if(!blksize) {
|
if(!blksize) {
|
||||||
failf(data, "invalid blocksize value in OACK packet");
|
failf(data, "invalid blocksize value in OACK packet");
|
||||||
@@ -374,12 +385,12 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
|
|||||||
/* could realloc pkt buffers here, but the spec doesn't call out
|
/* could realloc pkt buffers here, but the spec doesn't call out
|
||||||
* support for the server requesting a bigger blksize than the client
|
* support for the server requesting a bigger blksize than the client
|
||||||
* requests */
|
* requests */
|
||||||
failf(data, "%s (%d)",
|
failf(data, "%s (%ld)",
|
||||||
"server requested blksize larger than allocated", blksize);
|
"server requested blksize larger than allocated", blksize);
|
||||||
return CURLE_TFTP_ILLEGAL;
|
return CURLE_TFTP_ILLEGAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->blksize = blksize;
|
state->blksize = (int)blksize;
|
||||||
infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
|
infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
|
||||||
state->blksize, "requested", state->requested_blksize);
|
state->blksize, "requested", state->requested_blksize);
|
||||||
}
|
}
|
||||||
@@ -392,7 +403,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
|
|||||||
return CURLE_TFTP_ILLEGAL;
|
return CURLE_TFTP_ILLEGAL;
|
||||||
}
|
}
|
||||||
Curl_pgrsSetDownloadSize(data, tsize);
|
Curl_pgrsSetDownloadSize(data, tsize);
|
||||||
infof(data, "%s (%d)\n", "tsize parsed from OACK", tsize);
|
infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,13 +413,14 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
|
|||||||
static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
|
static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
|
||||||
char *buf, const char *option)
|
char *buf, const char *option)
|
||||||
{
|
{
|
||||||
if( ( strlen(option) + csize + 1U ) > state->blksize )
|
if( ( strlen(option) + csize + 1 ) > (size_t)state->blksize )
|
||||||
return 0;
|
return 0;
|
||||||
strcpy(buf, option);
|
strcpy(buf, option);
|
||||||
return( strlen(option) + 1 );
|
return( strlen(option) + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event)
|
static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
|
||||||
|
tftp_event_t event)
|
||||||
{
|
{
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||||
@@ -423,7 +435,8 @@ static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event
|
|||||||
return tftp_tx(state, event);
|
return tftp_tx(state, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event)
|
static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
|
||||||
|
tftp_event_t event)
|
||||||
{
|
{
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||||
@@ -441,6 +454,7 @@ static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event
|
|||||||
static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
|
static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
|
||||||
{
|
{
|
||||||
size_t sbytes;
|
size_t sbytes;
|
||||||
|
ssize_t senddata;
|
||||||
const char *mode = "octet";
|
const char *mode = "octet";
|
||||||
char *filename;
|
char *filename;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
@@ -506,18 +520,19 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
TFTP_OPTION_BLKSIZE);
|
TFTP_OPTION_BLKSIZE);
|
||||||
sbytes += tftp_option_add(state, sbytes,
|
sbytes += tftp_option_add(state, sbytes,
|
||||||
(char *)state->spacket.data+sbytes, buf );
|
(char *)state->spacket.data+sbytes, buf );
|
||||||
/* add timeout option */
|
/* add timeout option, this is the max time the session may live */
|
||||||
snprintf( buf, sizeof(buf), "%d", state->retry_time );
|
snprintf( buf, sizeof(buf), "%d", state->retry_time*state->retry_max );
|
||||||
sbytes += tftp_option_add(state, sbytes,
|
sbytes += tftp_option_add(state, sbytes,
|
||||||
(char *)state->spacket.data+sbytes,
|
(char *)state->spacket.data+sbytes,
|
||||||
TFTP_OPTION_INTERVAL);
|
TFTP_OPTION_INTERVAL);
|
||||||
sbytes += tftp_option_add(state, sbytes,
|
sbytes += tftp_option_add(state, sbytes,
|
||||||
(char *)state->spacket.data+sbytes, buf );
|
(char *)state->spacket.data+sbytes, buf );
|
||||||
|
|
||||||
if (sendto(state->sockfd, (void *)state->spacket.data,
|
senddata = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
sbytes, 0,
|
sbytes, 0,
|
||||||
state->conn->ip_addr->ai_addr,
|
state->conn->ip_addr->ai_addr,
|
||||||
state->conn->ip_addr->ai_addrlen) < 0) {
|
state->conn->ip_addr->ai_addrlen);
|
||||||
|
if(senddata != (ssize_t)sbytes) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
}
|
}
|
||||||
Curl_safefree(filename);
|
Curl_safefree(filename);
|
||||||
@@ -560,6 +575,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
**********************************************************/
|
**********************************************************/
|
||||||
static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
||||||
{
|
{
|
||||||
|
ssize_t sbytes;
|
||||||
int rblock;
|
int rblock;
|
||||||
struct SessionHandle *data = state->conn->data;
|
struct SessionHandle *data = state->conn->data;
|
||||||
|
|
||||||
@@ -584,10 +600,11 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
state->retries = 0;
|
state->retries = 0;
|
||||||
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
|
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
|
||||||
setpacketblock(&state->spacket, state->block);
|
setpacketblock(&state->spacket, state->block);
|
||||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
4, SEND_4TH_ARG,
|
4, SEND_4TH_ARG,
|
||||||
(struct sockaddr *)&state->remote_addr,
|
(struct sockaddr *)&state->remote_addr,
|
||||||
state->remote_addrlen) < 0) {
|
state->remote_addrlen);
|
||||||
|
if(sbytes < 0) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
@@ -599,6 +616,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
else {
|
else {
|
||||||
state->state = TFTP_STATE_RX;
|
state->state = TFTP_STATE_RX;
|
||||||
}
|
}
|
||||||
|
time(&state->rx_time);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TFTP_EVENT_OACK:
|
case TFTP_EVENT_OACK:
|
||||||
@@ -607,33 +625,38 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
state->retries = 0;
|
state->retries = 0;
|
||||||
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
|
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
|
||||||
setpacketblock(&state->spacket, state->block);
|
setpacketblock(&state->spacket, state->block);
|
||||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
4, SEND_4TH_ARG,
|
4, SEND_4TH_ARG,
|
||||||
(struct sockaddr *)&state->remote_addr,
|
(struct sockaddr *)&state->remote_addr,
|
||||||
state->remote_addrlen) < 0) {
|
state->remote_addrlen);
|
||||||
|
if(sbytes < 0) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we're ready to RX data */
|
/* we're ready to RX data */
|
||||||
state->state = TFTP_STATE_RX;
|
state->state = TFTP_STATE_RX;
|
||||||
|
time(&state->rx_time);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TFTP_EVENT_TIMEOUT:
|
case TFTP_EVENT_TIMEOUT:
|
||||||
/* Increment the retry count and fail if over the limit */
|
/* Increment the retry count and fail if over the limit */
|
||||||
state->retries++;
|
state->retries++;
|
||||||
infof(data,
|
infof(data,
|
||||||
"Timeout waiting for block %d ACK. Retries = %d\n", state->retries);
|
"Timeout waiting for block %d ACK. Retries = %d\n",
|
||||||
|
state->block+1, state->retries);
|
||||||
if(state->retries > state->retry_max) {
|
if(state->retries > state->retry_max) {
|
||||||
state->error = TFTP_ERR_TIMEOUT;
|
state->error = TFTP_ERR_TIMEOUT;
|
||||||
state->state = TFTP_STATE_FIN;
|
state->state = TFTP_STATE_FIN;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Resend the previous ACK and check all sbytes were sent */
|
/* Resend the previous ACK */
|
||||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
4, SEND_4TH_ARG,
|
4, SEND_4TH_ARG,
|
||||||
(struct sockaddr *)&state->remote_addr,
|
(struct sockaddr *)&state->remote_addr,
|
||||||
state->remote_addrlen) < 0) {
|
state->remote_addrlen);
|
||||||
|
/* Check all sbytes were sent */
|
||||||
|
if(sbytes<0) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
@@ -641,6 +664,14 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TFTP_EVENT_ERROR:
|
case TFTP_EVENT_ERROR:
|
||||||
|
setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
|
||||||
|
setpacketblock(&state->spacket, state->block);
|
||||||
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
|
4, SEND_4TH_ARG,
|
||||||
|
(struct sockaddr *)&state->remote_addr,
|
||||||
|
state->remote_addrlen);
|
||||||
|
/* don't bother with the return code, but if the socket is still up we
|
||||||
|
* should be a good TFTP client and let the server know we're done */
|
||||||
state->state = TFTP_STATE_FIN;
|
state->state = TFTP_STATE_FIN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -662,8 +693,8 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = state->conn->data;
|
struct SessionHandle *data = state->conn->data;
|
||||||
|
ssize_t sbytes;
|
||||||
int rblock;
|
int rblock;
|
||||||
int readcount;
|
|
||||||
CURLcode res = CURLE_OK;
|
CURLcode res = CURLE_OK;
|
||||||
struct SingleRequest *k = &data->req;
|
struct SingleRequest *k = &data->req;
|
||||||
|
|
||||||
@@ -685,38 +716,40 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
res = CURLE_SEND_ERROR;
|
res = CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Re-send the data packet and check all sbytes were sent */
|
/* Re-send the data packet */
|
||||||
if(sendto(state->sockfd, (void *)&state->spacket,
|
sbytes = sendto(state->sockfd, (void *)&state->spacket,
|
||||||
4+state->sbytes, SEND_4TH_ARG,
|
4+state->sbytes, SEND_4TH_ARG,
|
||||||
(struct sockaddr *)&state->remote_addr,
|
(struct sockaddr *)&state->remote_addr,
|
||||||
state->remote_addrlen) < 0) {
|
state->remote_addrlen);
|
||||||
|
/* Check all sbytes were sent */
|
||||||
|
if(sbytes<0) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
res = CURLE_SEND_ERROR;
|
res = CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
/* fall-through */
|
|
||||||
case TFTP_EVENT_OACK:
|
|
||||||
/* This is the expected packet. Reset the counters and send the next
|
/* This is the expected packet. Reset the counters and send the next
|
||||||
block */
|
block */
|
||||||
|
time(&state->rx_time);
|
||||||
state->block++;
|
state->block++;
|
||||||
state->retries = 0;
|
state->retries = 0;
|
||||||
setpacketevent(&state->spacket, TFTP_EVENT_DATA);
|
setpacketevent(&state->spacket, TFTP_EVENT_DATA);
|
||||||
setpacketblock(&state->spacket, state->block);
|
setpacketblock(&state->spacket, state->block);
|
||||||
if(state->block > 1 && state->sbytes < state->blksize) {
|
if(state->block > 1 && state->sbytes < (int)state->blksize) {
|
||||||
state->state = TFTP_STATE_FIN;
|
state->state = TFTP_STATE_FIN;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
res = Curl_fillreadbuffer(state->conn, (int)state->blksize, &readcount);
|
res = Curl_fillreadbuffer(state->conn, (size_t)state->blksize,
|
||||||
state->sbytes = readcount;
|
&state->sbytes);
|
||||||
if(res)
|
if(res)
|
||||||
return res;
|
return res;
|
||||||
/* Send the data packet and check all sbytes were sent */
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
|
||||||
4+state->sbytes, SEND_4TH_ARG,
|
4+state->sbytes, SEND_4TH_ARG,
|
||||||
(struct sockaddr *)&state->remote_addr,
|
(struct sockaddr *)&state->remote_addr,
|
||||||
state->remote_addrlen) < 0) {
|
state->remote_addrlen);
|
||||||
|
/* Check all sbytes were sent */
|
||||||
|
if(sbytes<0) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
@@ -729,18 +762,20 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
/* Increment the retry counter and log the timeout */
|
/* Increment the retry counter and log the timeout */
|
||||||
state->retries++;
|
state->retries++;
|
||||||
infof(data, "Timeout waiting for block %d ACK. "
|
infof(data, "Timeout waiting for block %d ACK. "
|
||||||
" Retries = %d\n", state->retries);
|
" Retries = %d\n", state->block+1, state->retries);
|
||||||
/* Decide if we've had enough */
|
/* Decide if we've had enough */
|
||||||
if(state->retries > state->retry_max) {
|
if(state->retries > state->retry_max) {
|
||||||
state->error = TFTP_ERR_TIMEOUT;
|
state->error = TFTP_ERR_TIMEOUT;
|
||||||
state->state = TFTP_STATE_FIN;
|
state->state = TFTP_STATE_FIN;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Re-send the data packet and check all sbytes were sent */
|
/* Re-send the data packet */
|
||||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
4+state->sbytes, SEND_4TH_ARG,
|
4+state->sbytes, SEND_4TH_ARG,
|
||||||
(struct sockaddr *)&state->remote_addr,
|
(struct sockaddr *)&state->remote_addr,
|
||||||
state->remote_addrlen) < 0) {
|
state->remote_addrlen);
|
||||||
|
/* Check all sbytes were sent */
|
||||||
|
if(sbytes<0) {
|
||||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
}
|
}
|
||||||
@@ -751,6 +786,15 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
|
|
||||||
case TFTP_EVENT_ERROR:
|
case TFTP_EVENT_ERROR:
|
||||||
state->state = TFTP_STATE_FIN;
|
state->state = TFTP_STATE_FIN;
|
||||||
|
setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
|
||||||
|
setpacketblock(&state->spacket, state->block);
|
||||||
|
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||||
|
4, SEND_4TH_ARG,
|
||||||
|
(struct sockaddr *)&state->remote_addr,
|
||||||
|
state->remote_addrlen);
|
||||||
|
/* don't bother with the return code, but if the socket is still up we
|
||||||
|
* should be a good TFTP client and let the server know we're done */
|
||||||
|
state->state = TFTP_STATE_FIN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -761,6 +805,59 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_translate_code
|
||||||
|
*
|
||||||
|
* Translate internal error codes to CURL error codes
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static CURLcode tftp_translate_code(tftp_error_t error)
|
||||||
|
{
|
||||||
|
CURLcode code = CURLE_OK;
|
||||||
|
|
||||||
|
if(error != TFTP_ERR_NONE) {
|
||||||
|
switch(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_REMOTE_DISK_FULL;
|
||||||
|
break;
|
||||||
|
case TFTP_ERR_UNDEF:
|
||||||
|
case TFTP_ERR_ILLEGAL:
|
||||||
|
code = CURLE_TFTP_ILLEGAL;
|
||||||
|
break;
|
||||||
|
case TFTP_ERR_UNKNOWNID:
|
||||||
|
code = CURLE_TFTP_UNKNOWNID;
|
||||||
|
break;
|
||||||
|
case TFTP_ERR_EXISTS:
|
||||||
|
code = CURLE_REMOTE_FILE_EXISTS;
|
||||||
|
break;
|
||||||
|
case TFTP_ERR_NOSUCHUSER:
|
||||||
|
code = CURLE_TFTP_NOSUCHUSER;
|
||||||
|
break;
|
||||||
|
case TFTP_ERR_TIMEOUT:
|
||||||
|
code = CURLE_OPERATION_TIMEDOUT;
|
||||||
|
break;
|
||||||
|
case TFTP_ERR_NORESPONSE:
|
||||||
|
code = CURLE_COULDNT_CONNECT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
code= CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
code = CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(code);
|
||||||
|
}
|
||||||
|
|
||||||
/**********************************************************
|
/**********************************************************
|
||||||
*
|
*
|
||||||
* tftp_state_machine
|
* tftp_state_machine
|
||||||
@@ -883,11 +980,11 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
|
|||||||
/* If not already bound, bind to any interface, random UDP port. If it is
|
/* If not already bound, bind to any interface, random UDP port. If it is
|
||||||
* reused or a custom local port was desired, this has already been done!
|
* reused or a custom local port was desired, this has already been done!
|
||||||
*
|
*
|
||||||
* We once used the size of the local_addr struct as the third argument for
|
* We once used the size of the local_addr struct as the third argument
|
||||||
* bind() to better work with IPv6 or whatever size the struct could have,
|
* for bind() to better work with IPv6 or whatever size the struct could
|
||||||
* but we learned that at least Tru64, AIX and IRIX *requires* the size of
|
* have, but we learned that at least Tru64, AIX and IRIX *requires* the
|
||||||
* that argument to match the exact size of a 'sockaddr_in' struct when
|
* size of that argument to match the exact size of a 'sockaddr_in' struct
|
||||||
* running IPv4-only.
|
* when running IPv4-only.
|
||||||
*
|
*
|
||||||
* Therefore we use the size from the address we connected to, which we
|
* Therefore we use the size from the address we connected to, which we
|
||||||
* assume uses the same IP version and thus hopefully this works for both
|
* assume uses the same IP version and thus hopefully this works for both
|
||||||
@@ -920,38 +1017,341 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
|
|||||||
static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
|
static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
|
||||||
bool premature)
|
bool premature)
|
||||||
{
|
{
|
||||||
|
CURLcode code = CURLE_OK;
|
||||||
|
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
|
||||||
(void)status; /* unused */
|
(void)status; /* unused */
|
||||||
(void)premature; /* not used */
|
(void)premature; /* not used */
|
||||||
|
|
||||||
Curl_pgrsDone(conn);
|
Curl_pgrsDone(conn);
|
||||||
|
|
||||||
return CURLE_OK;
|
/* If we have encountered an error */
|
||||||
|
code = tftp_translate_code(state->error);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_getsock
|
||||||
|
*
|
||||||
|
* The getsock callback
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
|
return GETSOCK_READSOCK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_receive_packet
|
||||||
|
*
|
||||||
|
* Called once select fires and data is ready on the socket
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static CURLcode tftp_receive_packet(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct Curl_sockaddr_storage fromaddr;
|
||||||
|
curl_socklen_t fromlen;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
struct SingleRequest *k = &data->req;
|
||||||
|
|
||||||
|
/* Receive the packet */
|
||||||
|
fromlen = sizeof(fromaddr);
|
||||||
|
state->rbytes = (int)recvfrom(state->sockfd,
|
||||||
|
(void *)state->rpacket.data,
|
||||||
|
state->blksize+4,
|
||||||
|
0,
|
||||||
|
(struct sockaddr *)&fromaddr,
|
||||||
|
&fromlen);
|
||||||
|
if(state->remote_addrlen==0) {
|
||||||
|
memcpy(&state->remote_addr, &fromaddr, fromlen);
|
||||||
|
state->remote_addrlen = fromlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check packet length */
|
||||||
|
if(state->rbytes < 4) {
|
||||||
|
failf(data, "Received too short packet");
|
||||||
|
/* Not a timeout, but how best to handle it? */
|
||||||
|
state->event = TFTP_EVENT_TIMEOUT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* The event is given by the TFTP packet time */
|
||||||
|
state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
|
||||||
|
|
||||||
|
switch(state->event) {
|
||||||
|
case TFTP_EVENT_DATA:
|
||||||
|
/* Don't pass to the client empty or retransmitted packets */
|
||||||
|
if(state->rbytes > 4 &&
|
||||||
|
((state->block+1) == getrpacketblock(&state->rpacket))) {
|
||||||
|
result = Curl_client_write(conn, CLIENTWRITE_BODY,
|
||||||
|
(char *)state->rpacket.data+4,
|
||||||
|
state->rbytes-4);
|
||||||
|
if(result) {
|
||||||
|
tftp_state_machine(state, TFTP_EVENT_ERROR);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
k->bytecount += state->rbytes-4;
|
||||||
|
Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TFTP_EVENT_ERROR:
|
||||||
|
state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
|
||||||
|
infof(data, "%s\n", (const char *)state->rpacket.data+4);
|
||||||
|
break;
|
||||||
|
case TFTP_EVENT_ACK:
|
||||||
|
break;
|
||||||
|
case TFTP_EVENT_OACK:
|
||||||
|
result = tftp_parse_option_ack(state,
|
||||||
|
(const char *)state->rpacket.data+2,
|
||||||
|
state->rbytes-2);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
break;
|
||||||
|
case TFTP_EVENT_RRQ:
|
||||||
|
case TFTP_EVENT_WRQ:
|
||||||
|
default:
|
||||||
|
failf(data, "%s", "Internal error: Unexpected packet");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the progress meter */
|
||||||
|
if(Curl_pgrsUpdate(conn)) {
|
||||||
|
tftp_state_machine(state, TFTP_EVENT_ERROR);
|
||||||
|
return CURLE_ABORTED_BY_CALLBACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_state_timeout
|
||||||
|
*
|
||||||
|
* Check if timeouts have been reached
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
|
||||||
|
{
|
||||||
|
time_t current;
|
||||||
|
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
*event = TFTP_EVENT_NONE;
|
||||||
|
|
||||||
|
time(¤t);
|
||||||
|
if(current > state->max_time) {
|
||||||
|
DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
|
||||||
|
(long)current, (long)state->max_time));
|
||||||
|
state->error = TFTP_ERR_TIMEOUT;
|
||||||
|
state->state = TFTP_STATE_FIN;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
else if (current > state->rx_time+state->retry_time) {
|
||||||
|
if (event)
|
||||||
|
*event = TFTP_EVENT_TIMEOUT;
|
||||||
|
time(&state->rx_time); /* update even though we received nothing */
|
||||||
|
return(state->max_time-current);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return(state->max_time-current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_easy_statemach
|
||||||
|
*
|
||||||
|
* Handle easy request until completion
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static CURLcode tftp_easy_statemach(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int check_time = 0;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
|
||||||
|
/* Run the TFTP State Machine */
|
||||||
|
for(;
|
||||||
|
(state->state != TFTP_STATE_FIN) && (result == CURLE_OK);
|
||||||
|
result=tftp_state_machine(state, state->event) ) {
|
||||||
|
|
||||||
|
/* Wait until ready to read or timeout occurs */
|
||||||
|
rc=Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD,
|
||||||
|
state->retry_time * 1000);
|
||||||
|
|
||||||
|
if(rc == -1) {
|
||||||
|
/* bail out */
|
||||||
|
int error = SOCKERRNO;
|
||||||
|
failf(data, "%s", Curl_strerror(conn, error));
|
||||||
|
state->event = TFTP_EVENT_ERROR;
|
||||||
|
}
|
||||||
|
else if(rc==0) {
|
||||||
|
/* A timeout occured */
|
||||||
|
state->event = TFTP_EVENT_TIMEOUT;
|
||||||
|
|
||||||
|
/* Force a look at transfer timeouts */
|
||||||
|
check_time = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = tftp_receive_packet(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for transfer timeout every 10 blocks, or after timeout */
|
||||||
|
if(check_time%10==0) {
|
||||||
|
/* ignore the event here as Curl_socket_ready() handles
|
||||||
|
* retransmission timeouts inside the easy state mach */
|
||||||
|
tftp_state_timeout(conn, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell curl we're done */
|
||||||
|
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_multi_statemach
|
||||||
|
*
|
||||||
|
* Handle single RX socket event and return
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
tftp_event_t event;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
long timeout_ms = tftp_state_timeout(conn, &event);
|
||||||
|
|
||||||
|
*done = FALSE;
|
||||||
|
|
||||||
|
if(timeout_ms <= 0) {
|
||||||
|
failf(data, "TFTP response timeout");
|
||||||
|
return CURLE_OPERATION_TIMEDOUT;
|
||||||
|
}
|
||||||
|
else if (event != TFTP_EVENT_NONE) {
|
||||||
|
result = tftp_state_machine(state, event);
|
||||||
|
if(result != CURLE_OK)
|
||||||
|
return(result);
|
||||||
|
*done = (bool)(state->state == TFTP_STATE_FIN);
|
||||||
|
if(*done)
|
||||||
|
/* Tell curl we're done */
|
||||||
|
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* no timeouts to handle, check our socket */
|
||||||
|
rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0);
|
||||||
|
|
||||||
|
if(rc == -1) {
|
||||||
|
/* bail out */
|
||||||
|
int error = SOCKERRNO;
|
||||||
|
failf(data, "%s", Curl_strerror(conn, error));
|
||||||
|
state->event = TFTP_EVENT_ERROR;
|
||||||
|
}
|
||||||
|
else if(rc != 0) {
|
||||||
|
result = tftp_receive_packet(conn);
|
||||||
|
if(result != CURLE_OK)
|
||||||
|
return(result);
|
||||||
|
result = tftp_state_machine(state, state->event);
|
||||||
|
if(result != CURLE_OK)
|
||||||
|
return(result);
|
||||||
|
*done = (bool)(state->state == TFTP_STATE_FIN);
|
||||||
|
if(*done)
|
||||||
|
/* Tell curl we're done */
|
||||||
|
result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
}
|
||||||
|
/* if rc == 0, then select() timed out */
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_doing
|
||||||
|
*
|
||||||
|
* Called from multi.c while DOing
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
result = tftp_multi_statemach(conn, dophase_done);
|
||||||
|
|
||||||
|
if(*dophase_done) {
|
||||||
|
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
*
|
||||||
|
* tftp_peform
|
||||||
|
*
|
||||||
|
* Entry point for transfer from tftp_do, sarts state mach
|
||||||
|
*
|
||||||
|
**********************************************************/
|
||||||
|
static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
|
||||||
|
*dophase_done = FALSE;
|
||||||
|
|
||||||
|
result = tftp_state_machine(state, TFTP_EVENT_INIT);
|
||||||
|
|
||||||
|
if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
|
||||||
|
return(result);
|
||||||
|
|
||||||
|
if(conn->data->state.used_interface == Curl_if_multi)
|
||||||
|
tftp_multi_statemach(conn, dophase_done);
|
||||||
|
else {
|
||||||
|
result = tftp_easy_statemach(conn);
|
||||||
|
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*dophase_done)
|
||||||
|
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************
|
/**********************************************************
|
||||||
*
|
*
|
||||||
* tftp
|
* tftp_do
|
||||||
*
|
*
|
||||||
* The do callback
|
* The do callback
|
||||||
*
|
*
|
||||||
* This callback handles the entire TFTP transfer
|
* This callback initiates the TFTP transfer
|
||||||
*
|
*
|
||||||
**********************************************************/
|
**********************************************************/
|
||||||
|
|
||||||
static CURLcode tftp_do(struct connectdata *conn, bool *done)
|
static CURLcode tftp_do(struct connectdata *conn, bool *done)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
|
||||||
tftp_state_data_t *state;
|
tftp_state_data_t *state;
|
||||||
tftp_event_t event;
|
|
||||||
CURLcode code;
|
CURLcode code;
|
||||||
int rc;
|
|
||||||
struct Curl_sockaddr_storage fromaddr;
|
|
||||||
curl_socklen_t fromlen;
|
|
||||||
int check_time = 0;
|
|
||||||
struct SingleRequest *k = &data->req;
|
|
||||||
|
|
||||||
*done = TRUE;
|
*done = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Since connections can be re-used between SessionHandles, this might be a
|
Since connections can be re-used between SessionHandles, this might be a
|
||||||
@@ -968,156 +1368,11 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
state = (tftp_state_data_t *)conn->proto.tftpc;
|
state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||||
|
|
||||||
/* Run the TFTP State Machine */
|
code = tftp_perform(conn, done);
|
||||||
for(code=tftp_state_machine(state, TFTP_EVENT_INIT);
|
|
||||||
(state->state != TFTP_STATE_FIN) && (code == CURLE_OK);
|
|
||||||
code=tftp_state_machine(state, event) ) {
|
|
||||||
|
|
||||||
/* Wait until ready to read or timeout occurs */
|
|
||||||
rc=Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD,
|
|
||||||
(int)(state->retry_time * 1000));
|
|
||||||
|
|
||||||
if(rc == -1) {
|
|
||||||
/* bail out */
|
|
||||||
int error = SOCKERRNO;
|
|
||||||
failf(data, "%s", 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 = (ssize_t)recvfrom(state->sockfd,
|
|
||||||
(void *)state->rpacket.data,
|
|
||||||
state->blksize+4,
|
|
||||||
0,
|
|
||||||
(struct sockaddr *)&fromaddr,
|
|
||||||
&fromlen);
|
|
||||||
if(state->remote_addrlen==0) {
|
|
||||||
memcpy(&state->remote_addr, &fromaddr, fromlen);
|
|
||||||
state->remote_addrlen = fromlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sanity check packet length */
|
|
||||||
if(state->rbytes < 4) {
|
|
||||||
failf(data, "Received too short packet");
|
|
||||||
/* Not a timeout, but how best to handle it? */
|
|
||||||
event = TFTP_EVENT_TIMEOUT;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
/* The event is given by the TFTP packet time */
|
|
||||||
event = (tftp_event_t)getrpacketevent(&state->rpacket);
|
|
||||||
|
|
||||||
switch(event) {
|
|
||||||
case TFTP_EVENT_DATA:
|
|
||||||
/* Don't pass to the client empty or retransmitted packets */
|
|
||||||
if(state->rbytes > 4 &&
|
|
||||||
((state->block+1) == getrpacketblock(&state->rpacket))) {
|
|
||||||
code = Curl_client_write(conn, CLIENTWRITE_BODY,
|
|
||||||
(char *)state->rpacket.data+4,
|
|
||||||
state->rbytes-4);
|
|
||||||
if(code)
|
|
||||||
return code;
|
|
||||||
k->bytecount += state->rbytes-4;
|
|
||||||
Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TFTP_EVENT_ERROR:
|
|
||||||
state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
|
|
||||||
infof(data, "%s\n", (const char *)state->rpacket.data+4);
|
|
||||||
break;
|
|
||||||
case TFTP_EVENT_ACK:
|
|
||||||
break;
|
|
||||||
case TFTP_EVENT_OACK:
|
|
||||||
code = tftp_parse_option_ack(state,
|
|
||||||
(const char *)state->rpacket.data+2,
|
|
||||||
(int)state->rbytes-2);
|
|
||||||
if(code)
|
|
||||||
return code;
|
|
||||||
break;
|
|
||||||
case TFTP_EVENT_RRQ:
|
|
||||||
case TFTP_EVENT_WRQ:
|
|
||||||
default:
|
|
||||||
failf(data, "%s", "Internal error: Unexpected packet");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the progress meter */
|
|
||||||
if(Curl_pgrsUpdate(conn))
|
|
||||||
return CURLE_ABORTED_BY_CALLBACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for transfer timeout every 10 blocks, or after timeout */
|
|
||||||
if(check_time%10==0) {
|
|
||||||
time_t current;
|
|
||||||
time(¤t);
|
|
||||||
if(current>state->max_time) {
|
|
||||||
DEBUGF(infof(data, "timeout: %d > %d\n",
|
|
||||||
current, state->max_time));
|
|
||||||
state->error = TFTP_ERR_TIMEOUT;
|
|
||||||
state->state = TFTP_STATE_FIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if(code)
|
|
||||||
return code;
|
|
||||||
|
|
||||||
/* Tell curl we're done */
|
|
||||||
code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
|
||||||
if(code)
|
|
||||||
return code;
|
|
||||||
|
|
||||||
/* If we have encountered an error */
|
/* If we have encountered an error */
|
||||||
if(state->error != TFTP_ERR_NONE) {
|
code = tftp_translate_code(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_REMOTE_DISK_FULL;
|
|
||||||
break;
|
|
||||||
case TFTP_ERR_UNDEF:
|
|
||||||
case TFTP_ERR_ILLEGAL:
|
|
||||||
code = CURLE_TFTP_ILLEGAL;
|
|
||||||
break;
|
|
||||||
case TFTP_ERR_UNKNOWNID:
|
|
||||||
code = CURLE_TFTP_UNKNOWNID;
|
|
||||||
break;
|
|
||||||
case TFTP_ERR_EXISTS:
|
|
||||||
code = CURLE_REMOTE_FILE_EXISTS;
|
|
||||||
break;
|
|
||||||
case TFTP_ERR_NOSUCHUSER:
|
|
||||||
code = CURLE_TFTP_NOSUCHUSER;
|
|
||||||
break;
|
|
||||||
case TFTP_ERR_TIMEOUT:
|
|
||||||
code = CURLE_OPERATION_TIMEDOUT;
|
|
||||||
break;
|
|
||||||
case TFTP_ERR_NORESPONSE:
|
|
||||||
code = CURLE_COULDNT_CONNECT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
code= CURLE_ABORTED_BY_CALLBACK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
code = CURLE_OK;
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user