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 |
293
CHANGES
293
CHANGES
@@ -6,10 +6,294 @@
|
||||
|
||||
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)
|
||||
- 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
|
||||
meter/callback during FTP command/response sequences. It turned out it was
|
||||
really lame before and now the progress meter SHOULD get called at least
|
||||
once per second.
|
||||
@@ -70,6 +354,11 @@ Kamil Dudka (15 Nov 2009)
|
||||
(and in particular the list of required libraries) even if a path is given
|
||||
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)
|
||||
- curl-config now accepts '--configure' to see what arguments was
|
||||
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
|
||||
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)
|
||||
- Kevin Baughman provided a fix preventing libcurl-NSS from crash on doubly
|
||||
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
|
||||
Command line options: 132
|
||||
curl_easy_setopt() options: 163
|
||||
Command line options: 136
|
||||
curl_easy_setopt() options: 174
|
||||
Public functions in libcurl: 58
|
||||
Known libcurl bindings: 38
|
||||
Known libcurl bindings: 39
|
||||
Contributors: 761
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o support SSL_FILETYPE_ENGINE for client certificate
|
||||
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:
|
||||
|
||||
@@ -26,6 +37,23 @@ This release includes the following bugfixes:
|
||||
o HTTP proxy tunnel re-used connection even if tunnel got disabled
|
||||
o SSL lib post-close write
|
||||
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:
|
||||
|
||||
@@ -36,6 +64,10 @@ advice from friends like these:
|
||||
|
||||
Yang Tse, Kamil Dudka, Christian Schmitz, Constantine Sapuntzakis,
|
||||
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)
|
||||
|
||||
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
|
||||
@@ -12,11 +12,4 @@ To be addressed in 7.19.8 (planned release: January 2010)
|
||||
|
||||
253 - add option to disable SNI for TLS handshakes
|
||||
|
||||
257 - bug #2891595 DNS cache
|
||||
|
||||
258 - bug #2891591 Curl_dns_entry
|
||||
|
||||
259 - Avoding connection re-use when using CURLOPT_HTTPPROXYTUNNEL
|
||||
|
||||
260 -
|
||||
|
||||
261 -
|
||||
25
acinclude.m4
25
acinclude.m4
@@ -3190,7 +3190,22 @@ AC_DEFUN([CURL_CHECK_WIN32_LARGEFILE], [
|
||||
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 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.
|
||||
@@ -3198,6 +3213,8 @@ dnl
|
||||
dnl If pkg-config is present, check that it has info about the $module or
|
||||
dnl return "no" anyway!
|
||||
dnl
|
||||
dnl Optionally PKG_CONFIG_LIBDIR may be given as $pcdir.
|
||||
dnl
|
||||
|
||||
AC_DEFUN([CURL_CHECK_PKGCONFIG], [
|
||||
|
||||
@@ -3216,8 +3233,10 @@ AC_DEFUN([CURL_CHECK_PKGCONFIG], [
|
||||
if test x$PKGCONFIG != xno; then
|
||||
AC_MSG_CHECKING([for $1 options with pkg-config])
|
||||
dnl ask pkg-config about $1
|
||||
$PKGCONFIG --exists $1
|
||||
if test "$?" -ne "0"; then
|
||||
itexists=`CURL_EXPORT_PCDIR([$2]) dnl
|
||||
$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 variable to 'no'
|
||||
PKGCONFIG="no"
|
||||
|
||||
19
ares/CHANGES
19
ares/CHANGES
@@ -1,5 +1,24 @@
|
||||
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)
|
||||
- Larry Lansing fixed ares_parse_srv_reply to properly parse replies
|
||||
which might contain non-SRV answers, skipping over potential non-SRV
|
||||
|
||||
@@ -222,13 +222,19 @@ PDBTYPE_CONSOLIDATE = /pdbtype:consolidate
|
||||
!UNDEF PDBTYPE_CONSOLIDATE
|
||||
!ENDIF
|
||||
|
||||
!IF $(CC_VERS_NUM) <= 70
|
||||
RT_ERROR_CHECKING = /GZ
|
||||
!ELSE
|
||||
RT_ERROR_CHECKING = /RTCsu
|
||||
!ENDIF
|
||||
|
||||
# ----------------------------
|
||||
# Assorted commands and flags
|
||||
# ----------------------------
|
||||
|
||||
CC_CMD_REL = cl.exe /nologo $(RTLIB) /DNDEBUG /O2
|
||||
CC_CMD_DBG = cl.exe /nologo $(RTLIBD) /D_DEBUG /Od /Zi /GZ
|
||||
CC_CFLAGS = $(CFLAGS) /I. /W3 /GX /FD
|
||||
CC_CMD_DBG = cl.exe /nologo $(RTLIBD) /D_DEBUG /Od /Zi $(RT_ERROR_CHECKING)
|
||||
CC_CFLAGS = $(CFLAGS) /I. /W3 /EHsc /FD
|
||||
|
||||
RC_CMD_REL = rc.exe /l 0x409 /d "NDEBUG"
|
||||
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:
|
||||
|
||||
o in6_addr is not used in ares.h anymore, but a private ares_in6_addr is
|
||||
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
|
||||
o
|
||||
|
||||
Fixed:
|
||||
|
||||
o ares_parse_*_reply() functions now return ARES_EBADRESP instead of
|
||||
ARES_EBADNAME if the name in the response failed to decode
|
||||
o only expose/export symbols starting with 'ares_'
|
||||
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
|
||||
o closing of sockets on Windows systems
|
||||
o MSVC deprecated compiler options warnings
|
||||
o ares_process_fd() didn't check broken connections
|
||||
|
||||
Thanks go to these friendly people for their efforts and contributions:
|
||||
|
||||
Phil Blundell, Japheth Cleaver, Yang Tse, Gregor Jasny, Joshua Kwan,
|
||||
Timo Teras, Jakub Hrozek, John Engelhart, Larry Lansing
|
||||
Ingmar Runge, Laszlo Tamas Szabo, Yang Tse, Tommie Gannert
|
||||
|
||||
Have fun!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* $Id$ */
|
||||
|
||||
/* 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
|
||||
* 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);
|
||||
static void next_server(ares_channel channel, struct query *query,
|
||||
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_udp_socket(ares_channel channel, struct server_state *server);
|
||||
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.
|
||||
* See what's up and respond accordingly.
|
||||
*/
|
||||
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
|
||||
{
|
||||
struct timeval now = ares__tvnow();
|
||||
|
||||
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);
|
||||
processfds(channel, read_fds, ARES_SOCKET_BAD, write_fds, ARES_SOCKET_BAD);
|
||||
}
|
||||
|
||||
/* Something interesting happened on the wire, or there was a timeout.
|
||||
@@ -161,12 +171,7 @@ void ares_process_fd(ares_channel channel,
|
||||
file descriptors */
|
||||
ares_socket_t write_fd)
|
||||
{
|
||||
struct timeval now = ares__tvnow();
|
||||
|
||||
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);
|
||||
processfds(channel, NULL, read_fd, NULL, write_fd);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +179,8 @@ void ares_process_fd(ares_channel channel,
|
||||
* otherwise. This is mostly for HP-UX, which could return EAGAIN or
|
||||
* 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)
|
||||
{
|
||||
@@ -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
|
||||
* based on the 'nonblock' boolean argument. This function is highly portable.
|
||||
* setsocknonblock sets the given socket to either blocking or non-blocking
|
||||
* mode based on the 'nonblock' boolean argument. This function is highly
|
||||
* portable.
|
||||
*/
|
||||
static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
|
||||
int nonblock /* TRUE or FALSE */)
|
||||
@@ -856,7 +863,7 @@ static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
|
||||
#endif
|
||||
}
|
||||
|
||||
static int configure_socket(int s, ares_channel channel)
|
||||
static int configure_socket(ares_socket_t s, ares_channel channel)
|
||||
{
|
||||
setsocknonblock(s, TRUE);
|
||||
|
||||
@@ -902,10 +909,10 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
|
||||
|
||||
#ifdef TCP_NODELAY
|
||||
/*
|
||||
* Disable the Nagle algorithm (only relevant for TCP sockets, and thus not in
|
||||
* configure_socket). In general, in DNS lookups we're pretty much interested
|
||||
* in firing off a single request and then waiting for a reply, so batching
|
||||
* isn't very interesting in general.
|
||||
* Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
|
||||
* in configure_socket). In general, in DNS lookups we're pretty much
|
||||
* interested in firing off a single request and then waiting for a reply,
|
||||
* so batching isn't very interesting in general.
|
||||
*/
|
||||
opt = 1;
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
#define ARES_VERSION_MAJOR 1
|
||||
#define ARES_VERSION_MINOR 7
|
||||
#define ARES_VERSION_PATCH 0
|
||||
#define ARES_VERSION_PATCH 1
|
||||
#define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\
|
||||
(ARES_VERSION_MINOR<<8)|\
|
||||
(ARES_VERSION_PATCH))
|
||||
#define ARES_VERSION_STR "1.7.0-CVS"
|
||||
#define ARES_VERSION_STR "1.7.1-CVS"
|
||||
|
||||
#if (ARES_VERSION >= 0x010700)
|
||||
# define CARES_HAVE_ARES_LIBRARY_INIT 1
|
||||
|
||||
@@ -85,6 +85,9 @@
|
||||
/* FUNCTIONS */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have the closesocket function. */
|
||||
#define HAVE_CLOSESOCKET 1
|
||||
|
||||
/* Define if you have the gethostname function. */
|
||||
#define HAVE_GETHOSTNAME 1
|
||||
|
||||
|
||||
@@ -415,7 +415,7 @@ typedef int sig_atomic_t;
|
||||
* 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)
|
||||
#define getpwuid __32_getpwuid
|
||||
#endif
|
||||
@@ -425,7 +425,7 @@ typedef int sig_atomic_t;
|
||||
* Macro argv_item_t hides platform details to code using it.
|
||||
*/
|
||||
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#define argv_item_t __char_ptr32
|
||||
#else
|
||||
#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
|
||||
# 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_WARNINGS
|
||||
CURL_CHECK_OPTION_CURLDEBUG
|
||||
CURL_CHECK_OPTION_ARES
|
||||
|
||||
CURL_CHECK_PATH_SEPARATOR_REQUIRED
|
||||
|
||||
@@ -135,6 +136,7 @@ curl_verbose_msg="enabled (--disable-verbose)"
|
||||
curl_sspi_msg="no (--enable-sspi)"
|
||||
curl_ldap_msg="no (--enable-ldap / --with-ldap-lib / --with-lber-lib)"
|
||||
curl_ldaps_msg="no (--enable-ldaps)"
|
||||
curl_rtsp_msg="no (--enable-rtsp)"
|
||||
|
||||
dnl
|
||||
dnl Save anything in $LIBS for later
|
||||
@@ -318,8 +320,10 @@ AC_HELP_STRING([--disable-http],[Disable HTTP support]),
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
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_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP])
|
||||
AC_SUBST(CURL_DISABLE_RTSP, [1])
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
;;
|
||||
@@ -416,6 +420,32 @@ AC_HELP_STRING([--disable-ldaps],[Disable LDAPS support]),
|
||||
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_ARG_ENABLE(proxy,
|
||||
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_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 Check for built-in manual
|
||||
dnl **********************************************************************
|
||||
@@ -1154,7 +1235,6 @@ if test X"$OPT_SSL" != Xno; then
|
||||
CLEANLDFLAGS="$LDFLAGS"
|
||||
CLEANCPPFLAGS="$CPPFLAGS"
|
||||
CLEANLIBS="$LIBS"
|
||||
SAVE_PKG_CONFIG_LIBDIR="$PKG_CONFIG_LIBDIR"
|
||||
|
||||
case "$OPT_SSL" in
|
||||
yes)
|
||||
@@ -1182,10 +1262,9 @@ if test X"$OPT_SSL" != Xno; then
|
||||
dnl Try pkg-config even when cross-compiling. Since we
|
||||
dnl specify PKG_CONFIG_LIBDIR we're only looking where
|
||||
dnl the user told us to look
|
||||
PKG_CONFIG_LIBDIR=$OPT_SSL/lib/pkgconfig
|
||||
export PKG_CONFIG_LIBDIR
|
||||
AC_MSG_NOTICE([set PKG_CONFIG_LIBDIR to "$PKG_CONFIG_LIBDIR"])
|
||||
if test -e "$PKG_CONFIG_LIBDIR/openssl.pc"; then
|
||||
OPENSSL_PCDIR="$OPT_SSL/lib/pkgconfig"
|
||||
AC_MSG_NOTICE([PKG_CONFIG_LIBDIR will be set to "$OPENSSL_PCDIR"])
|
||||
if test -e "$OPENSSL_PCDIR/openssl.pc"; then
|
||||
PKGTEST="yes"
|
||||
fi
|
||||
|
||||
@@ -1202,12 +1281,17 @@ if test X"$OPT_SSL" != Xno; then
|
||||
|
||||
if test "$PKGTEST" = "yes"; then
|
||||
|
||||
CURL_CHECK_PKGCONFIG(openssl)
|
||||
CURL_CHECK_PKGCONFIG(openssl, [$OPENSSL_PCDIR])
|
||||
|
||||
if test "$PKGCONFIG" != "no" ; then
|
||||
SSL_LIBS=`$PKGCONFIG --libs-only-l openssl 2>/dev/null`
|
||||
SSL_LDFLAGS=`$PKGCONFIG --libs-only-L openssl 2>/dev/null`
|
||||
SSL_CPPFLAGS=`$PKGCONFIG --cflags-only-I openssl 2>/dev/null`
|
||||
SSL_LIBS=`CURL_EXPORT_PCDIR([$OPENSSL_PCDIR]) dnl
|
||||
$PKGCONFIG --libs-only-l 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_LDFLAGS: "$SSL_LDFLAGS"])
|
||||
@@ -1225,10 +1309,6 @@ if test X"$OPT_SSL" != Xno; then
|
||||
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
|
||||
CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS"
|
||||
LDFLAGS="$LDFLAGS $SSL_LDFLAGS"
|
||||
@@ -1346,6 +1426,7 @@ if test X"$OPT_SSL" != Xno; then
|
||||
AC_CHECK_FUNCS( RAND_status \
|
||||
RAND_screen \
|
||||
RAND_egd \
|
||||
ENGINE_cleanup \
|
||||
CRYPTO_cleanup_all_ex_data \
|
||||
SSL_get_shutdown )
|
||||
|
||||
@@ -1957,8 +2038,9 @@ CURL_CHECK_STRUCT_TIMEVAL
|
||||
CURL_VERIFY_RUNTIMELIBS
|
||||
|
||||
AC_CHECK_SIZEOF(size_t)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
CURL_CONFIGURE_LONG
|
||||
AC_CHECK_SIZEOF(time_t)
|
||||
AC_CHECK_SIZEOF(off_t)
|
||||
@@ -2194,81 +2276,8 @@ fi
|
||||
dnl set variable for use in automakefile(s)
|
||||
AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1)
|
||||
|
||||
aresembedded="unknown"
|
||||
configure_rundir=`pwd`
|
||||
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)
|
||||
CURL_CHECK_LIB_ARES
|
||||
AM_CONDITIONAL(USE_EMBEDDED_ARES, test x$embedded_ares = xyes)
|
||||
|
||||
dnl ************************************************************
|
||||
dnl disable verbose text strings
|
||||
@@ -2302,7 +2311,7 @@ AC_HELP_STRING([--disable-sspi],[Disable SSPI]),
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_WINDOWS_SSPI, 1, [to enable SSPI support])
|
||||
AC_SUBST(USE_WINDOWS_SSPI, [1])
|
||||
curl_sspi_msg="yes"
|
||||
curl_sspi_msg="enabled"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_WARN([--enable-sspi Ignored. Only supported on native Windows builds.])
|
||||
@@ -2460,7 +2469,7 @@ fi
|
||||
if test "x$HAVE_LIBZ" = "x1"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES libz"
|
||||
fi
|
||||
if test "x$HAVE_ARES" = "x1"; then
|
||||
if test "x$USE_ARES" = "x1"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
|
||||
fi
|
||||
if test "x$IDN_ENABLED" = "x1"; then
|
||||
@@ -2506,10 +2515,36 @@ fi
|
||||
if test "x$CURL_DISABLE_TFTP" != "x1"; then
|
||||
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TFTP"
|
||||
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
|
||||
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
|
||||
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
|
||||
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)
|
||||
|
||||
@@ -2525,8 +2560,11 @@ squeeze CURL_LIBS
|
||||
squeeze LIBCURL_LIBS
|
||||
squeeze TEST_SERVER_LIBS
|
||||
|
||||
squeeze SUPPORT_FEATURES
|
||||
squeeze SUPPORT_PROTOCOLS
|
||||
|
||||
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"
|
||||
fi
|
||||
|
||||
@@ -2584,6 +2622,8 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
|
||||
ca cert path: ${capath}
|
||||
LDAP support: ${curl_ldap_msg}
|
||||
LDAPS support: ${curl_ldaps_msg}
|
||||
RTSP support: ${curl_rtsp_msg}
|
||||
Protocols: ${SUPPORT_PROTOCOLS}
|
||||
])
|
||||
|
||||
if test "x$soname_bump" = "xyes"; then
|
||||
|
||||
@@ -63,6 +63,10 @@ Euphoria
|
||||
Written by Ray Smith
|
||||
http://rays-web.com/eulibcurl.htm
|
||||
|
||||
Falcon
|
||||
|
||||
http://www.falconpl.org/index.ftd?page_id=prjs&prj_id=curl
|
||||
|
||||
Ferite
|
||||
|
||||
Written by Paul Querna
|
||||
|
||||
@@ -874,9 +874,9 @@ REDUCING SIZE
|
||||
.comment section).
|
||||
|
||||
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
|
||||
an FTP-only library that is 87 KiB in size (as of libcurl version 7.19.1,
|
||||
using gcc 4.2.2).
|
||||
libcurl library for i386 Linux platforms that is only 98 KiB in size, and
|
||||
an FTP-only library that is 94 KiB in size (as of libcurl version 7.20.0,
|
||||
using gcc 4.3.3).
|
||||
|
||||
You may find that statically linking libcurl to your application will
|
||||
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
|
||||
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
|
||||
sends the 220 response or otherwise is dead slow, libcurl will not
|
||||
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."
|
||||
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
|
||||
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
|
||||
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
|
||||
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:
|
||||
|
||||
@@ -379,6 +379,7 @@ Judson Bishop
|
||||
Juergen Wilke
|
||||
Jukka Pihl
|
||||
Julian Noble
|
||||
Julien Chaffraix
|
||||
Jun-ichiro itojun Hagino
|
||||
Jurij Smakov
|
||||
Justin Fletcher
|
||||
|
||||
23
docs/TODO
23
docs/TODO
@@ -37,8 +37,7 @@
|
||||
5. HTTP
|
||||
5.1 Better persistency for HTTP 1.0
|
||||
5.2 support FF3 sqlite cookie files
|
||||
5.3 Sort outgoing cookies
|
||||
5.4 Rearrange request header order
|
||||
5.3 Rearrange request header order
|
||||
|
||||
6. TELNET
|
||||
6.1 ditch stdin
|
||||
@@ -105,6 +104,7 @@
|
||||
15.4 remove several functions
|
||||
15.5 remove CURLOPT_FAILONERROR
|
||||
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.
|
||||
http://curl.haxx.se/bug/feature.cgi?id=1871388
|
||||
|
||||
5.3 Sort outgoing cookies
|
||||
|
||||
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
|
||||
5.3 Rearrange request header order
|
||||
|
||||
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
|
||||
@@ -585,3 +578,13 @@ to provide the data to send.
|
||||
Remove support for a global DNS cache. Anything global is silly, and we
|
||||
already offer the share interface for the same functionality but done
|
||||
"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
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -21,7 +21,7 @@
|
||||
.\" * $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
|
||||
curl \- transfer a URL
|
||||
.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)
|
||||
|
||||
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
|
||||
.IP "--ftp-ssl"
|
||||
(FTP) Try to use SSL/TLS for the FTP connection. Reverts to a non-secure
|
||||
connection if the server doesn't support SSL/TLS. See also
|
||||
\fI--ftp-ssl-control\fP and \fI--ftp-ssl-reqd\fP for different levels of
|
||||
encryption required. (Added in 7.11.0)
|
||||
.IP "--ftp-pret"
|
||||
(FTP) Tell 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.
|
||||
(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"
|
||||
(FTP) Require SSL/TLS for the FTP login, clear for transfer. Allows secure
|
||||
authentication, but non-encrypted data transfers for efficiency. Fails the
|
||||
transfer if the server doesn't support SSL/TLS. (Added in 7.16.0)
|
||||
.IP "--ftp-ssl-reqd"
|
||||
(FTP) Require SSL/TLS for the FTP connection.
|
||||
Terminates the connection if the server doesn't support SSL/TLS.
|
||||
(Added in 7.15.5)
|
||||
.IP "--ssl-reqd"
|
||||
(FTP, POP3, IMAP, SMTP) Require SSL/TLS for the connection. Terminates the
|
||||
connection if the server doesn't support SSL/TLS. (Added in 7.20.0)
|
||||
|
||||
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"
|
||||
(FTP) Use CCC (Clear Command Channel)
|
||||
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
|
||||
as if a new session is started. Typical browsers always discard session
|
||||
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"
|
||||
(SSL) This option explicitly allows curl to perform "insecure" SSL connections
|
||||
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
|
||||
you'll send your authentication info (which is plaintext in the case of HTTP
|
||||
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>"
|
||||
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
|
||||
@@ -1079,7 +1100,7 @@ timestamp.
|
||||
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
|
||||
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
|
||||
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
|
||||
was previously wrongly documented and used as --socks without the number
|
||||
appended.)
|
||||
|
||||
This option (as well as \fI--socks4\fP) does not work with IPV6, FTPS or LDAP.
|
||||
.IP "--socks5-gssapi-service <servicename>"
|
||||
The default service name for a socks server is rcmd/server-fqdn. This option
|
||||
allows you to change it.
|
||||
@@ -1181,6 +1204,14 @@ TTYPE=<term> Sets the terminal type.
|
||||
XDISPLOC=<X display> Sets the X display location.
|
||||
|
||||
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>"
|
||||
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
|
||||
|
||||
@@ -453,7 +453,7 @@ int main(int argc, char **argv) {
|
||||
{
|
||||
FILE *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) ;
|
||||
|
||||
@@ -105,11 +105,14 @@ int main(int argc, char **argv)
|
||||
/* See how the transfers went */
|
||||
while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
|
||||
if (msg->msg == CURLMSG_DONE) {
|
||||
|
||||
int idx, found = 0;
|
||||
|
||||
/* 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) {
|
||||
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
|
||||
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)
|
||||
.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
|
||||
.nf
|
||||
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
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -21,7 +21,7 @@
|
||||
.\" * $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
|
||||
curl_easy_setopt \- set options for a curl easy handle
|
||||
.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
|
||||
the option details below.
|
||||
|
||||
NOTE: before 7.17.0 strings were not copied. Instead the user was forced keep
|
||||
them available until libcurl no longer needed them.
|
||||
Before version 7.17.0, strings were not copied. Instead the user was forced
|
||||
keep them available until libcurl no longer needed them.
|
||||
|
||||
The \fIhandle\fP is the return code from a \fIcurl_easy_init(3)\fP or
|
||||
\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.
|
||||
|
||||
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
|
||||
callbacks to add additional validation code for certificates, and even to
|
||||
change the actual URI of an HTTPS request (example used in the lib509 test
|
||||
libraries is necessary. For example, using this function allows you to use
|
||||
openssl callbacks to add additional validation code for certificates, and even
|
||||
to change the actual URI of an HTTPS request (example used in the lib509 test
|
||||
case). See also the example section for a replacement of the key, certificate
|
||||
and trust file settings.
|
||||
.IP CURLOPT_SSL_CTX_DATA
|
||||
@@ -401,6 +401,30 @@ follows:
|
||||
|
||||
You will need to override these definitions if they are different on your
|
||||
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
|
||||
.IP CURLOPT_ERRORBUFFER
|
||||
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
|
||||
(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
|
||||
\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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
by nature are scarce resources that will be busy at times so setting this
|
||||
value to something too low might cause unnecessary connection setup
|
||||
failures. (Added in 7.15.2)
|
||||
make libcurl do only one try for the exact port number. Port numbers by nature
|
||||
are scarce resources that will be busy at times so setting this value to
|
||||
something too low might cause unnecessary connection setup failures. (Added in
|
||||
7.15.2)
|
||||
.IP CURLOPT_DNS_CACHE_TIMEOUT
|
||||
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
|
||||
caching, or set to -1 to make the cached entries remain forever. By default,
|
||||
libcurl caches this info for 60 seconds.
|
||||
|
||||
NOTE: the name resolve functions of various libc implementations don't re-read
|
||||
name server information unless explicitly told so (for example, by calling
|
||||
The name resolve functions of various libc implementations don't re-read name
|
||||
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
|
||||
if DHCP has updated the server info, and this may look like a DNS cache issue
|
||||
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.
|
||||
|
||||
The CURLOPT_PROXYUSERNAME option should be used in same way as the
|
||||
\fICURLOPT_PROXYUSERPWD\fP is used. In comparison to \fICURLOPT_PROXYUSERPWD\fP
|
||||
the CURLOPT_PROXYUSERNAME allows the username to contain a colon,
|
||||
like in the following example: "sip:user@example.com".
|
||||
Note the CURLOPT_PROXYUSERNAME option is an alternative way to set the user name
|
||||
while connecting to Proxy. There is no meaning to use it together
|
||||
with the \fICURLOPT_PROXYUSERPWD\fP option.
|
||||
\fICURLOPT_PROXYUSERPWD\fP is used. In comparison to
|
||||
\fICURLOPT_PROXYUSERPWD\fP the CURLOPT_PROXYUSERNAME allows the username to
|
||||
contain a colon, like in the following example: "sip:user@example.com". The
|
||||
CURLOPT_PROXYUSERNAME option is an alternative way to set the user name while
|
||||
connecting to Proxy. There is no meaning to use it together with the
|
||||
\fICURLOPT_PROXYUSERPWD\fP option.
|
||||
|
||||
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)
|
||||
@@ -736,8 +763,8 @@ it finds suitable. libcurl will automatically select the one it finds most
|
||||
secure.
|
||||
.IP CURLAUTH_ANYSAFE
|
||||
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
|
||||
finds most secure.
|
||||
libcurl pick any it finds suitable. libcurl will automatically select the one
|
||||
it finds most secure.
|
||||
.RE
|
||||
.IP CURLOPT_PROXYAUTH
|
||||
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
|
||||
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
|
||||
it excludes the FILE protocol by default.
|
||||
.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
|
||||
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
|
||||
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
|
||||
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;"
|
||||
etc.
|
||||
|
||||
Note that this option sets the cookie header explictly in the outgoing
|
||||
request(s). If multiple requests are done due to authentication, followed
|
||||
redirections or similar, they will all get this cookie passed on.
|
||||
This option sets the cookie header explictly in the outgoing request(s). If
|
||||
multiple requests are done due to authentication, followed redirections or
|
||||
similar, they will all get this cookie passed on.
|
||||
|
||||
Using this option multiple times will only make the latest string override the
|
||||
previous ones.
|
||||
@@ -1045,14 +1072,27 @@ progress, and will simply stop the download when the server ends the
|
||||
connection. (added in 7.14.1)
|
||||
.IP CURLOPT_HTTP_CONTENT_DECODING
|
||||
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
|
||||
that libcurl has no default content decoding but requires you to use
|
||||
\fICURLOPT_ENCODING\fP for that. (added in 7.16.2)
|
||||
content decoding will be disabled. If set to 1 it is enabled. Libcurl has no
|
||||
default content decoding but requires you to use \fICURLOPT_ENCODING\fP for
|
||||
that. (added in 7.16.2)
|
||||
.IP CURLOPT_HTTP_TRANSFER_DECODING
|
||||
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
|
||||
(default). libcurl does chunked transfer decoding by default unless this
|
||||
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
|
||||
.IP CURLOPT_TFTP_BLKSIZE
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
@@ -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'.
|
||||
.RE
|
||||
(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
|
||||
.IP CURLOPT_TRANSFERTEXT
|
||||
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
|
||||
\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
|
||||
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
|
||||
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
|
||||
@@ -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
|
||||
mandatory.
|
||||
|
||||
Note that this option does not limit how much data libcurl will actually send,
|
||||
as that is controlled entirely by what the read callback returns.
|
||||
This option does not limit how much data libcurl will actually send, as that
|
||||
is controlled entirely by what the read callback returns.
|
||||
.IP CURLOPT_INFILESIZE_LARGE
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
Note that this option does not limit how much data libcurl will actually send,
|
||||
as that is controlled entirely by what the read callback returns.
|
||||
This option does not limit how much data libcurl will actually send, as that
|
||||
is controlled entirely by what the read callback returns.
|
||||
.IP CURLOPT_UPLOAD
|
||||
A parameter set to 1 tells the library to prepare for an upload. The
|
||||
\fICURLOPT_READDATA\fP and \fICURLOPT_INFILESIZE\fP or
|
||||
@@ -1387,7 +1538,8 @@ given limit. This concerns both FTP and HTTP transfers.
|
||||
.IP CURLOPT_TIMECONDITION
|
||||
Pass a long as parameter. This defines how the \fICURLOPT_TIMEVALUE\fP time
|
||||
value is treated. You can set this parameter to \fICURL_TIMECOND_IFMODSINCE\fP
|
||||
or \fICURL_TIMECOND_IFUNMODSINCE\fP. This feature applies to HTTP and FTP.
|
||||
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
|
||||
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
|
||||
unnecessarily.
|
||||
|
||||
Note that 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
|
||||
the \fICURLMOPT_MAXCONNECTS\fP option.
|
||||
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 the
|
||||
\fICURLMOPT_MAXCONNECTS\fP option.
|
||||
.IP CURLOPT_CLOSEPOLICY
|
||||
(Obsolete) This option does nothing.
|
||||
.IP CURLOPT_FRESH_CONNECT
|
||||
@@ -1549,10 +1701,9 @@ operations.
|
||||
If the crypto device cannot be set, \fICURLE_SSL_ENGINE_SETFAILED\fP is
|
||||
returned.
|
||||
|
||||
Note that even though this option doesn't need any parameter, in some
|
||||
configurations \fIcurl_easy_setopt\fP might be defined as a macro taking
|
||||
exactly three arguments. Therefore, it's recommended to pass 1 as parameter to
|
||||
this option.
|
||||
Even though this option doesn't need any parameter, in some configurations
|
||||
\fIcurl_easy_setopt\fP might be defined as a macro taking exactly three
|
||||
arguments. Therefore, it's recommended to pass 1 as parameter to this option.
|
||||
.IP CURLOPT_SSLVERSION
|
||||
Pass a long as parameter to control what version of SSL/TLS to attempt to use.
|
||||
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
|
||||
even indicate an accessible file.
|
||||
|
||||
Note that option is by default set to the system path where libcurl's cacert
|
||||
bundle is assumed to be stored, as established at build time.
|
||||
This option is by default set to the system path where libcurl's cacert bundle
|
||||
is assumed to be stored, as established at build time.
|
||||
|
||||
When built against NSS, this is the directory that the NSS certificate
|
||||
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
|
||||
the peer certificate is performed to verify the issuer is indeed the one
|
||||
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
|
||||
from a specific branch of the tree.
|
||||
is useful in multi-level PKI where one needs to enforce that the peer
|
||||
certificate is from a specific branch of the tree.
|
||||
|
||||
This option makes sense only when used in combination with the
|
||||
\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
|
||||
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
|
||||
found in the CRL does not trigger this specific error. (Added in 7.19.0)
|
||||
A failure in certificate verification due to a revocation information found in
|
||||
the CRL does not trigger this specific error. (Added in 7.19.0)
|
||||
.IP CURLOPT_CERTINFO
|
||||
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
|
||||
@@ -1712,7 +1863,7 @@ You'll find more details about the NSS cipher lists on this URL:
|
||||
.IP CURLOPT_SSL_SESSIONID_CACHE
|
||||
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
|
||||
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
|
||||
require you to disable this in order for you to succeed. (Added in 7.16.0)
|
||||
.IP CURLOPT_KRBLEVEL
|
||||
@@ -1740,9 +1891,9 @@ libcurl defaults to using \fB~/.ssh/id_dsa.pub\fP.
|
||||
(Added in 7.16.1)
|
||||
.IP CURLOPT_SSH_PRIVATE_KEYFILE
|
||||
Pass a char * pointing to a file name for your private key. If not used,
|
||||
libcurl defaults to using \fB~/.ssh/id_dsa\fP.
|
||||
If the file is password-protected, set the password with \fICURLOPT_KEYPASSWD\fP.
|
||||
(Added in 7.16.1)
|
||||
libcurl defaults to using \fB~/.ssh/id_dsa\fP. If the file is
|
||||
password-protected, set the password with \fICURLOPT_KEYPASSWD\fP. (Added in
|
||||
7.16.1)
|
||||
.IP CURLOPT_SSH_KNOWNHOSTS
|
||||
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
|
||||
@@ -1761,9 +1912,9 @@ MUST return one of the following return codes to tell libcurl how to act:
|
||||
.IP CURLKHSTAT_FINE_ADD_TO_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
|
||||
to the known_host pool kept in memory if it wasn't already present there. Note
|
||||
that the adding of data to the file is done by completely replacing the file
|
||||
with a new copy, so the permissions of the file must allow this.
|
||||
to the known_host pool kept in memory if it wasn't already present there. The
|
||||
adding of data to the file is done by completely replacing the file with a new
|
||||
copy, so the permissions of the file must allow this.
|
||||
.IP CURLKHSTAT_FINE
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
this function returns. Otherwise it will contain the higher descriptor number
|
||||
libcurl set.
|
||||
|
||||
You should also be aware that when doing select(), you should consider using a
|
||||
rather small (single-digit number of seconds) timeout and call
|
||||
\fIcurl_multi_perform\fP regularly - even if no activity has been seen on the
|
||||
fd_sets - as otherwise libcurl-internal retries and timeouts may not work as
|
||||
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.
|
||||
When doing select(), you should use \fBcurl_multi_timeout\fP to figure out how
|
||||
long to wait for action. Call \fIcurl_multi_perform\fP even if no activity has
|
||||
been seen on the fd_sets after the timeout expires as otherwise internal
|
||||
retries and timeouts may not work as you'd think and want.
|
||||
.SH RETURN VALUE
|
||||
CURLMcode type, general libcurl multi interface error code. See
|
||||
\fIlibcurl-errors(3)\fP
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_multi_init "(3), "
|
||||
.BR curl_multi_timeout "(3) "
|
||||
.BR curl_multi_cleanup "(3), " curl_multi_init "(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
|
||||
transfers less "running". You can then call \fIcurl_multi_info_read(3)\fP to
|
||||
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,
|
||||
there is no longer any transfers in progress.
|
||||
.SH "RETURN VALUE"
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
|
||||
If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this basically means that you
|
||||
should call \fIcurl_multi_perform\fP again, before you select() on more
|
||||
actions. You don't have to do it immediately, but the return code means that
|
||||
libcurl may have more data available to return or that there may be more data
|
||||
to send off before it is "satisfied". Do note that \fIcurl_multi_perform(3)\fP
|
||||
will return \fICURLM_CALL_MULTI_PERFORM\fP only when it wants to be called
|
||||
again \fBimmediately\fP. When things are fine and there is nothing immediate
|
||||
it wants done, it'll return \fICURLM_OK\fP and you need to wait for \&"action"
|
||||
and then call this function again.
|
||||
Before version 7.20.0: If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this
|
||||
basically means that you should call \fIcurl_multi_perform\fP again, before
|
||||
you select() on more actions. You don't have to do it immediately, but the
|
||||
return code means that libcurl may have more data available to return or that
|
||||
there may be more data to send off before it is "satisfied". Do note that
|
||||
\fIcurl_multi_perform(3)\fP will return \fICURLM_CALL_MULTI_PERFORM\fP only
|
||||
when it wants to be called again \fBimmediately\fP. When things are fine and
|
||||
there is nothing immediate it wants done, it'll return \fICURLM_OK\fP and you
|
||||
need to wait for \&"action" and then call this function again.
|
||||
|
||||
NOTE that this only returns errors etc regarding the whole multi stack. Problems
|
||||
still might have occurred on individual transfers even when this
|
||||
This function only returns errors etc regarding the whole multi stack.
|
||||
Problems still might have occurred on individual transfers even when this
|
||||
function returns \fICURLM_OK\fP.
|
||||
.SH "TYPICAL USAGE"
|
||||
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.
|
||||
|
||||
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
|
||||
reaches zero, all transfers are complete/done. Note that when you call
|
||||
of running easy handles within the multi handle. When this number reaches
|
||||
zero, all transfers are complete/done. When you call
|
||||
\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
|
||||
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"
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
|
||||
Legacy: If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this basically means
|
||||
that you should call \fIcurl_multi_socket_action(3)\fP again, before you wait
|
||||
for more actions on libcurl's sockets. You don't have to do it immediately,
|
||||
but the return code means that libcurl may have more data available to return
|
||||
or that there may be more data to send off before it is "satisfied".
|
||||
Before version 7.20.0: If you receive \fICURLM_CALL_MULTI_PERFORM\fP, this
|
||||
basically means that you should call \fIcurl_multi_socket_action(3)\fP again
|
||||
before you wait for more actions on libcurl's sockets. You don't have to do it
|
||||
immediately, but the return code means that libcurl may have more data
|
||||
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),
|
||||
\fICURLM_CALL_MULTI_PERFORM\fP or \fICURLM_CALL_MULTI_SOKCET\fP will not be
|
||||
returned and no application needs to care about them.
|
||||
|
||||
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.
|
||||
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"
|
||||
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
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -21,7 +21,7 @@
|
||||
.\" * $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
|
||||
libcurl-errors \- error codes in libcurl
|
||||
.SH DESCRIPTION
|
||||
@@ -70,6 +70,11 @@ either a PASV or a EPSV command. The server is flawed.
|
||||
.IP "CURLE_FTP_WEIRD_227_FORMAT (14)"
|
||||
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.
|
||||
.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)"
|
||||
An internal failure to lookup the host used for the new connection.
|
||||
.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.
|
||||
.IP "CURLE_HTTP_RETURNED_ERROR (22)"
|
||||
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
|
||||
CURLE_HTTP_NOT_FOUND.)
|
||||
returns an error code that is >= 400.
|
||||
.IP "CURLE_WRITE_ERROR (23)"
|
||||
An error occurred when writing received data to a local file, or an error was
|
||||
returned to libcurl from a write callback.
|
||||
.IP "CURLE_UPLOAD_FAILED (25)"
|
||||
Failed starting the upload. For FTP, the server typically denied the STOR
|
||||
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)"
|
||||
There was a problem reading a local file or an error returned by the read
|
||||
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
|
||||
more. Could be certificates (file formats, paths, permissions), passwords, and
|
||||
others.
|
||||
.IP "CURLE_FTP_BAD_DOWNLOAD_RESUME (36)"
|
||||
Attempting FTP resume beyond file size.
|
||||
.IP "CURLE_BAD_DOWNLOAD_RESUME (36)"
|
||||
The download could not be resumed because the specified offset was out of the
|
||||
file boundary.
|
||||
.IP "CURLE_FILE_COULDNT_READ_FILE (37)"
|
||||
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?
|
||||
@@ -138,8 +142,7 @@ Internal error. A function was called with a bad parameter.
|
||||
.IP "CURLE_INTERFACE_FAILED (45)"
|
||||
Interface error. A specified outgoing interface could not be used. Set which
|
||||
interface to use for outgoing connections' source IP address with
|
||||
CURLOPT_INTERFACE. (This error code was formerly known as
|
||||
CURLE_HTTP_PORT_FAILED.)
|
||||
CURLOPT_INTERFACE.
|
||||
.IP "CURLE_TOO_MANY_REDIRECTS (47)"
|
||||
Too many redirects. When following redirects, libcurl hit the maximum amount.
|
||||
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_DICT],[Defined if libcurl supports DICT])
|
||||
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_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
|
||||
# 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
|
||||
_libcurl_protocols="$_libcurl_protocols HTTPS"
|
||||
|
||||
# FTPS wasn't standards-compliant until version
|
||||
# 7.11.0
|
||||
# 7.11.0 (0x070b00 == 461568)
|
||||
if test $_libcurl_version -ge 461568; then
|
||||
_libcurl_protocols="$_libcurl_protocols FTPS"
|
||||
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
|
||||
|
||||
for _libcurl_protocol in $_libcurl_protocols ; do
|
||||
|
||||
@@ -37,7 +37,7 @@ CURLE_FAILED_INIT 7.1
|
||||
CURLE_FILESIZE_EXCEEDED 7.10.8
|
||||
CURLE_FILE_COULDNT_READ_FILE 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_RECONNECT 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_STOR_FILE 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_PRET_FAILED 7.20.0
|
||||
CURLE_FTP_QUOTE_ERROR 7.1 7.17.0
|
||||
CURLE_FTP_SSL_FAILED - 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_OUT_OF_MEMORY 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_RANGE_ERROR 7.17.0
|
||||
CURLE_READ_ERROR 7.1
|
||||
CURLE_RECV_ERROR 7.13.0
|
||||
CURLE_REMOTE_ACCESS_DENIED 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_SHARE_IN_USE - 7.17.0
|
||||
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_SETFAILED 7.9.3
|
||||
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_TELNET_OPTION_SYNTAX 7.7
|
||||
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_USE_EPRT 7.10.5
|
||||
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_HEADERDATA 7.10
|
||||
CURLOPT_HEADERFUNCTION 7.7.2
|
||||
CURLOPT_HTTP200ALIASES 7.10.3
|
||||
CURLOPT_HTTPAUTH 7.10.6
|
||||
@@ -259,6 +273,8 @@ CURLOPT_LOCALPORT 7.15.2
|
||||
CURLOPT_LOCALPORTRANGE 7.15.2
|
||||
CURLOPT_LOW_SPEED_LIMIT 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_MAXFILESIZE 7.10.8
|
||||
CURLOPT_MAXFILESIZE_LARGE 7.11.0
|
||||
@@ -374,10 +390,17 @@ CURLPROTO_FTP 7.19.4
|
||||
CURLPROTO_FTPS 7.19.4
|
||||
CURLPROTO_HTTP 7.19.4
|
||||
CURLPROTO_HTTPS 7.19.4
|
||||
CURLPROTO_IMAP 7.20.0
|
||||
CURLPROTO_IMAPS 7.20.0
|
||||
CURLPROTO_LDAP 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_SFTP 7.19.4
|
||||
CURLPROTO_SMTP 7.20.0
|
||||
CURLPROTO_SMTPS 7.20.0
|
||||
CURLPROTO_TELNET 7.19.4
|
||||
CURLPROTO_TFTP 7.19.4
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -47,6 +47,11 @@
|
||||
#include <stdio.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! */
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
@@ -66,7 +71,8 @@
|
||||
require it! */
|
||||
#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
|
||||
defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
|
||||
defined(ANDROID)
|
||||
defined(ANDROID) || \
|
||||
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
@@ -236,14 +242,6 @@ typedef curl_socket_t
|
||||
curlsocktype purpose,
|
||||
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 {
|
||||
CURLIOE_OK, /* I/O operation successful */
|
||||
CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
|
||||
@@ -407,6 +405,10 @@ typedef enum {
|
||||
wrong format (Added in 7.19.0) */
|
||||
CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
|
||||
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! */
|
||||
} CURLcode;
|
||||
|
||||
@@ -613,6 +615,13 @@ typedef enum {
|
||||
#define CURLPROTO_DICT (1<<9)
|
||||
#define CURLPROTO_FILE (1<<10)
|
||||
#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 */
|
||||
|
||||
/* 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
|
||||
in a timely manner. */
|
||||
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
|
||||
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 */
|
||||
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 */
|
||||
} CURLoption;
|
||||
|
||||
@@ -1315,6 +1358,7 @@ typedef enum {
|
||||
#define CURLOPT_WRITEDATA CURLOPT_FILE
|
||||
#define CURLOPT_READDATA CURLOPT_INFILE
|
||||
#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
|
||||
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
|
||||
|
||||
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
|
||||
enum {
|
||||
@@ -1327,6 +1371,25 @@ enum {
|
||||
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. */
|
||||
enum CURL_NETRC_OPTION {
|
||||
CURL_NETRC_IGNORED, /* The .netrc will never be read.
|
||||
@@ -1696,9 +1759,13 @@ typedef enum {
|
||||
CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33,
|
||||
CURLINFO_CERTINFO = CURLINFO_SLIST + 34,
|
||||
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! */
|
||||
|
||||
CURLINFO_LASTONE = 35
|
||||
CURLINFO_LASTONE = 39
|
||||
} CURLINFO;
|
||||
|
||||
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
|
||||
|
||||
@@ -370,16 +370,7 @@
|
||||
# define CURL_SIZEOF_CURL_SOCKLEN_T 4
|
||||
|
||||
#elif defined(__VMS)
|
||||
# if defined(__alpha) || defined(__ia64)
|
||||
# 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
|
||||
# if defined(__VAX)
|
||||
# define CURL_SIZEOF_LONG 4
|
||||
# define CURL_TYPEOF_CURL_OFF_T long
|
||||
# define CURL_FORMAT_CURL_OFF_T "ld"
|
||||
@@ -388,6 +379,15 @@
|
||||
# define CURL_SIZEOF_CURL_OFF_T 4
|
||||
# define CURL_SUFFIX_CURL_OFF_T L
|
||||
# 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
|
||||
# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
|
||||
# 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
|
||||
* 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_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 */
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
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
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 19
|
||||
#define LIBCURL_VERSION_PATCH 8
|
||||
#define LIBCURL_VERSION_MINOR 20
|
||||
#define LIBCURL_VERSION_PATCH 0
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
|
||||
@@ -54,7 +54,7 @@
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBCURL_VERSION_NUM 0x071308
|
||||
#define LIBCURL_VERSION_NUM 0x071400
|
||||
|
||||
/*
|
||||
* 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
|
||||
LIB_ARG = $(OBJ_BASE)\stat\wlib.arg
|
||||
|
||||
OBJS = $(OBJ_DIR)\base64.obj $(OBJ_DIR)\connect.obj &
|
||||
$(OBJ_DIR)\content_encoding.obj $(OBJ_DIR)\cookie.obj &
|
||||
$(OBJ_DIR)\curl_addrinfo.obj $(OBJ_DIR)\dict.obj &
|
||||
$(OBJ_DIR)\easy.obj $(OBJ_DIR)\escape.obj &
|
||||
$(OBJ_DIR)\file.obj $(OBJ_DIR)\formdata.obj &
|
||||
$(OBJ_DIR)\ftp.obj $(OBJ_DIR)\getenv.obj &
|
||||
$(OBJ_DIR)\getinfo.obj $(OBJ_DIR)\gtls.obj &
|
||||
$(OBJ_DIR)\hash.obj $(OBJ_DIR)\hostares.obj &
|
||||
$(OBJ_DIR)\hostasyn.obj $(OBJ_DIR)\hostip.obj &
|
||||
$(OBJ_DIR)\hostip4.obj $(OBJ_DIR)\hostip6.obj &
|
||||
$(OBJ_DIR)\hostsyn.obj $(OBJ_DIR)\hostthre.obj &
|
||||
$(OBJ_DIR)\http.obj $(OBJ_DIR)\http_chunks.obj &
|
||||
$(OBJ_DIR)\http_digest.obj $(OBJ_DIR)\http_negotiate.obj &
|
||||
$(OBJ_DIR)\http_ntlm.obj $(OBJ_DIR)\if2ip.obj &
|
||||
$(OBJ_DIR)\inet_ntop.obj $(OBJ_DIR)\inet_pton.obj &
|
||||
$(OBJ_DIR)\krb4.obj $(OBJ_DIR)\ldap.obj &
|
||||
$(OBJ_DIR)\llist.obj $(OBJ_DIR)\md5.obj &
|
||||
$(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
|
||||
# Unfortunately, we can't include Makefile.inc here because wmake doesn't
|
||||
# use backslash as the line continuation character by default
|
||||
CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c &
|
||||
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c &
|
||||
ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c &
|
||||
netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c &
|
||||
krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c &
|
||||
multi.c content_encoding.c share.c http_digest.c md5.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 &
|
||||
curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c
|
||||
|
||||
OBJS = $(CSOURCES:.c=.obj)
|
||||
OBJS = $OBJ_DIR\$(OBJS: = $OBJ_DIR\)
|
||||
|
||||
#
|
||||
# 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\multi.h ..\include\curl\curl.h curl_memrchr.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
|
||||
# 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 \
|
||||
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
|
||||
|
||||
@@ -84,9 +84,9 @@ if SONAME_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
|
||||
VERSIONINFO=-version-info 5:1:1
|
||||
VERSIONINFO=-version-info 6:0:2
|
||||
endif
|
||||
|
||||
# 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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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_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.transfer o.url o.version o.strtoofft o.sslgen o.gtls \
|
||||
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:
|
||||
@@ -44,6 +45,9 @@ o.curl_memrchr: c.curl_memrchr
|
||||
o.curl_rand: 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
|
||||
gcc $(compileropts) -c -o dict.o c.dict
|
||||
|
||||
@@ -92,6 +96,9 @@ o.http_chunks: c.http_chunks
|
||||
o.if2ip: 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
|
||||
gcc $(compileropts) -c -o inet_ntop.o c.inet_ntop
|
||||
|
||||
@@ -116,9 +123,18 @@ o.netrc: c.netrc
|
||||
o.parsedate: 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
|
||||
gcc $(compileropts) -c -o progress.o c.progress
|
||||
|
||||
o.rtsp: c.rtsp
|
||||
gcc $(compileropts) -c -o rtsp.o c.rtsp
|
||||
|
||||
o.security: c.security
|
||||
gcc $(compileropts) -c -o security.o c.security
|
||||
|
||||
@@ -131,6 +147,9 @@ o.sendf: c.sendf
|
||||
o.slist: 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
|
||||
gcc $(compileropts) -c -o speedcheck.o c.speedcheck
|
||||
|
||||
|
||||
@@ -453,6 +453,7 @@ X_OBJS= \
|
||||
$(DIROBJ)\curl_memrchr.obj \
|
||||
$(DIROBJ)\curl_rand.obj \
|
||||
$(DIROBJ)\curl_sspi.obj \
|
||||
$(DIROBJ)\curl_threads.obj \
|
||||
$(DIROBJ)\dict.obj \
|
||||
$(DIROBJ)\easy.obj \
|
||||
$(DIROBJ)\escape.obj \
|
||||
@@ -476,6 +477,7 @@ X_OBJS= \
|
||||
$(DIROBJ)\http_negotiate.obj \
|
||||
$(DIROBJ)\http_ntlm.obj \
|
||||
$(DIROBJ)\if2ip.obj \
|
||||
$(DIROBJ)\imap.obj \
|
||||
$(DIROBJ)\inet_ntop.obj \
|
||||
$(DIROBJ)\inet_pton.obj \
|
||||
$(DIROBJ)\ldap.obj \
|
||||
@@ -487,12 +489,16 @@ X_OBJS= \
|
||||
$(DIROBJ)\netrc.obj \
|
||||
$(DIROBJ)\nonblock.obj \
|
||||
$(DIROBJ)\parsedate.obj \
|
||||
$(DIROBJ)\pingpong.obj \
|
||||
$(DIROBJ)\pop3.obj \
|
||||
$(DIROBJ)\progress.obj \
|
||||
$(DIROBJ)\rawstr.obj \
|
||||
$(DIROBJ)\rtsp.obj \
|
||||
$(DIROBJ)\select.obj \
|
||||
$(DIROBJ)\sendf.obj \
|
||||
$(DIROBJ)\share.obj \
|
||||
$(DIROBJ)\slist.obj \
|
||||
$(DIROBJ)\smtp.obj \
|
||||
$(DIROBJ)\socks.obj \
|
||||
$(DIROBJ)\socks_gssapi.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__)
|
||||
# define HAVE_FREEADDRINFO 1
|
||||
# define HAVE_GETADDRINFO 1
|
||||
# define HAVE_GETADDRINFO_THREADSAFE 1
|
||||
# define HAVE_GETNAMEINFO 1
|
||||
# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
||||
# define HAVE_FREEADDRINFO 1
|
||||
# define HAVE_GETADDRINFO 1
|
||||
# define HAVE_GETADDRINFO_THREADSAFE 1
|
||||
# define HAVE_GETNAMEINFO 1
|
||||
# elif defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# define HAVE_FREEADDRINFO 1
|
||||
# define HAVE_GETADDRINFO 1
|
||||
# define HAVE_GETADDRINFO_THREADSAFE 1
|
||||
# define HAVE_GETNAMEINFO 1
|
||||
# endif
|
||||
#endif
|
||||
@@ -503,6 +506,24 @@
|
||||
# define USE_WIN32_SMALL_FILES
|
||||
#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 */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
@@ -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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -64,7 +64,7 @@
|
||||
#undef in_addr_t
|
||||
#define in_addr_t unsigned long
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#endif
|
||||
@@ -89,6 +89,7 @@
|
||||
#include "inet_ntop.h"
|
||||
#include "inet_pton.h"
|
||||
#include "sslgen.h" /* for Curl_ssl_check_cxn() */
|
||||
#include "progress.h"
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
@@ -192,7 +193,8 @@ long Curl_timeleft(struct connectdata *conn,
|
||||
#define WAITCONN_FDSET_ERROR 2
|
||||
|
||||
static
|
||||
int waitconnect(curl_socket_t sockfd, /* socket */
|
||||
int waitconnect(struct connectdata *conn,
|
||||
curl_socket_t sockfd, /* socket */
|
||||
long timeout_msec)
|
||||
{
|
||||
int rc;
|
||||
@@ -203,21 +205,34 @@ int waitconnect(curl_socket_t sockfd, /* socket */
|
||||
(void)verifyconnect(sockfd, NULL);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
|
||||
/* 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)
|
||||
/* error, no connect here, try next */
|
||||
return WAITCONN_SELECT_ERROR;
|
||||
|
||||
else if(0 == rc)
|
||||
/* timeout, no connect today */
|
||||
else if(0 == rc) {
|
||||
/* timeout */
|
||||
timeout_msec -= 1000;
|
||||
if(timeout_msec <= 0)
|
||||
return WAITCONN_TIMEOUT;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(rc & CURL_CSELECT_ERR)
|
||||
/* error condition caught */
|
||||
return WAITCONN_FDSET_ERROR;
|
||||
|
||||
/* we have a connect! */
|
||||
break;
|
||||
}
|
||||
return WAITCONN_CONNECTED;
|
||||
}
|
||||
|
||||
@@ -370,7 +385,7 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
for(;;) {
|
||||
if( bind(sockfd, sock, sizeof_sa) >= 0) {
|
||||
/* we succeeded to bind */
|
||||
struct Curl_sockaddr_storage add;
|
||||
@@ -382,13 +397,13 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
error, Curl_strerror(conn, error));
|
||||
return CURLE_INTERFACE_FAILED;
|
||||
}
|
||||
infof(data, "Local port: %d\n", port);
|
||||
infof(data, "Local port: %hu\n", port);
|
||||
conn->bits.bound = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
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 */
|
||||
/* We re-use/clobber the port variable here below */
|
||||
if(sock->sa_family == AF_INET)
|
||||
@@ -400,7 +415,7 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
data->state.os_errno = error = SOCKERRNO;
|
||||
failf(data, "bind failed with errno %d: %s",
|
||||
@@ -553,7 +568,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||
Curl_expire(data, allow);
|
||||
|
||||
/* check for connect without timeout as we want to return immediately */
|
||||
rc = waitconnect(sockfd, 0);
|
||||
rc = waitconnect(conn, sockfd, 0);
|
||||
|
||||
if(WAITCONN_CONNECTED == rc) {
|
||||
int error;
|
||||
@@ -566,7 +581,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||
data->state.os_errno = error;
|
||||
infof(data, "Connection failed\n");
|
||||
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));
|
||||
code = CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
@@ -586,7 +601,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||
if(trynextip(conn, sockindex, connected)) {
|
||||
error = SOCKERRNO;
|
||||
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));
|
||||
code = CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
@@ -719,12 +734,13 @@ singleipconnect(struct connectdata *conn,
|
||||
|
||||
if(data->set.fopensocket)
|
||||
/*
|
||||
* If the opensocket callback is set, all the destination address information
|
||||
* is passed to the callback. Depending on this information the callback may
|
||||
* opt to abort the connection, this is indicated returning CURL_SOCKET_BAD;
|
||||
* otherwise it will return a not-connected socket. When the callback returns
|
||||
* a valid socket the destination address information might have been changed
|
||||
* and this 'new' address will actually be used here to connect.
|
||||
* If the opensocket callback is set, all the destination address
|
||||
* information is passed to the callback. Depending on this information the
|
||||
* callback may opt to abort the connection, this is indicated returning
|
||||
* CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
|
||||
* the callback returns a valid socket the destination address information
|
||||
* might have been changed and this 'new' address will actually be used
|
||||
* here to connect.
|
||||
*/
|
||||
sockfd = data->set.fopensocket(data->set.opensocket_client,
|
||||
CURLSOCKTYPE_IPCXN,
|
||||
@@ -823,7 +839,7 @@ singleipconnect(struct connectdata *conn,
|
||||
case EAGAIN:
|
||||
#endif
|
||||
#endif
|
||||
rc = waitconnect(sockfd, timeout_ms);
|
||||
rc = waitconnect(conn, sockfd, timeout_ms);
|
||||
break;
|
||||
default:
|
||||
/* 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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -40,7 +40,7 @@
|
||||
(doing so will reduce code size slightly). */
|
||||
#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_1 0x8b
|
||||
@@ -285,8 +285,8 @@ Curl_unencode_gzip_write(struct connectdata *conn,
|
||||
return process_zlib_error(conn, z);
|
||||
}
|
||||
k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* we must parse the gzip header ourselves */
|
||||
if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -681,7 +681,8 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
|
||||
if(c->running)
|
||||
/* Only show this when NOT reading the cookies from a file */
|
||||
infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %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,
|
||||
co->domain, co->path, co->expires);
|
||||
|
||||
@@ -774,6 +775,18 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
|
||||
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()
|
||||
@@ -794,6 +807,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
struct Cookie *co;
|
||||
time_t now = time(NULL);
|
||||
struct Cookie *mainco=NULL;
|
||||
size_t matches = 0;
|
||||
|
||||
if(!c || !c->cookies)
|
||||
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 */
|
||||
mainco = newco;
|
||||
|
||||
matches++;
|
||||
}
|
||||
else {
|
||||
fail:
|
||||
/* failure, clear up the allocated chain and return NULL */
|
||||
while(mainco) {
|
||||
co = mainco->next;
|
||||
@@ -851,6 +868,36 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -909,7 +956,7 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies)
|
||||
{
|
||||
struct Cookie *first, *curr, *next, *prev = NULL;
|
||||
|
||||
if(!cookies->cookies || !cookies->cookies)
|
||||
if(!cookies || !cookies->cookies)
|
||||
return;
|
||||
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -38,7 +38,7 @@
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
# include <in.h>
|
||||
# include <inet.h>
|
||||
# include <stdlib.h>
|
||||
@@ -365,7 +365,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
|
||||
{
|
||||
Curl_addrinfo *ai;
|
||||
|
||||
#if defined(VMS) && \
|
||||
#if defined(__VMS) && \
|
||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||
#pragma pointer_size save
|
||||
#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[1] = NULL; /* terminate list of entries */
|
||||
|
||||
#if defined(VMS) && \
|
||||
#if defined(__VMS) && \
|
||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||
#pragma pointer_size restore
|
||||
#pragma message enable PTRMISMATCH
|
||||
@@ -447,8 +447,7 @@ curl_dofreeaddrinfo(struct addrinfo *freethis,
|
||||
int line, const char *source)
|
||||
{
|
||||
(freeaddrinfo)(freethis);
|
||||
if(logfile)
|
||||
fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
|
||||
curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
|
||||
source, line, (void *)freethis);
|
||||
}
|
||||
#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
|
||||
@@ -471,17 +470,13 @@ curl_dogetaddrinfo(const char *hostname,
|
||||
int line, const char *source)
|
||||
{
|
||||
int res=(getaddrinfo)(hostname, service, hints, result);
|
||||
if(0 == res) {
|
||||
if(0 == res)
|
||||
/* success */
|
||||
if(logfile)
|
||||
fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
|
||||
curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
|
||||
source, line, (void *)*result);
|
||||
}
|
||||
else {
|
||||
if(logfile)
|
||||
fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
|
||||
else
|
||||
curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
|
||||
source, line);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
# include <in.h>
|
||||
# include <inet.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
|
||||
* 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);
|
||||
if(rc != CURLE_OK) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
|
||||
rc, curl_easy_strerror(rc));
|
||||
"CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
|
||||
(int)rc, curl_easy_strerror(rc));
|
||||
}
|
||||
return(rc);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
#ifdef HAVE_ICONV
|
||||
/* do the translation ourselves */
|
||||
char *input_ptr, *output_ptr;
|
||||
@@ -942,8 +943,8 @@ CURLcode Curl_convert_from_network(struct SessionHandle *data,
|
||||
rc = data->set.convfromnetwork(buffer, length);
|
||||
if(rc != CURLE_OK) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
|
||||
rc, curl_easy_strerror(rc));
|
||||
"CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
|
||||
(int)rc, curl_easy_strerror(rc));
|
||||
}
|
||||
return(rc);
|
||||
}
|
||||
@@ -1003,11 +1004,12 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
|
||||
rc = data->set.convfromutf8(buffer, length);
|
||||
if(rc != CURLE_OK) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
|
||||
rc, curl_easy_strerror(rc));
|
||||
"CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
|
||||
(int)rc, curl_easy_strerror(rc));
|
||||
}
|
||||
return(rc);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
#ifdef HAVE_ICONV
|
||||
/* do the translation ourselves */
|
||||
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
|
||||
* 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)) {
|
||||
/* just copy this */
|
||||
ns[strindex++]=in;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* encode it */
|
||||
newlen += 2; /* the size grows with two, since this'll become a %XX */
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -23,6 +23,18 @@
|
||||
*
|
||||
* $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
|
||||
extern const struct Curl_handler Curl_handler_file;
|
||||
#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
|
||||
* 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;
|
||||
}
|
||||
} while(nread == sizeof(buffer));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if(ptr->length != append(arg, ptr->line, ptr->length)) {
|
||||
Curl_formclean(&data);
|
||||
return -1;
|
||||
|
||||
121
lib/ftp.h
121
lib/ftp.h
@@ -1,5 +1,5 @@
|
||||
#ifndef __FTP_H
|
||||
#define __FTP_H
|
||||
#ifndef HEADER_CURL_FTP_H
|
||||
#define HEADER_CURL_FTP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -23,6 +23,8 @@
|
||||
* $Id$
|
||||
***************************************************************************/
|
||||
|
||||
#include "pingpong.h"
|
||||
|
||||
#ifndef CURL_DISABLE_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;
|
||||
#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_nbftpsendf(struct connectdata *, const char *fmt, ...);
|
||||
CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
|
||||
int *ftpcode);
|
||||
#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 <string.h>
|
||||
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <unixlib.h>
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,7 @@ char *GetEnv(const char *variable)
|
||||
return (env[0] != '\0')?strdup(env):NULL;
|
||||
#else
|
||||
char *env = getenv(variable);
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
if(env && strcmp("HOME",variable) == 0)
|
||||
env = decc_translate_vms(env);
|
||||
#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
|
||||
* 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 */
|
||||
*param_longp = data->info.timecond;
|
||||
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:
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -46,7 +46,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
@@ -72,6 +72,7 @@
|
||||
#include "inet_pton.h"
|
||||
#include "connect.h"
|
||||
#include "select.h"
|
||||
#include "progress.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#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
|
||||
* 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
|
||||
*/
|
||||
|
||||
static int ares_waitperform(struct connectdata *conn, int timeout_ms)
|
||||
static int waitperform(struct connectdata *conn, int timeout_ms)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
int nfds;
|
||||
@@ -192,7 +193,7 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
|
||||
|
||||
*dns = NULL;
|
||||
|
||||
ares_waitperform(conn, 0);
|
||||
waitperform(conn, 0);
|
||||
|
||||
if(conn->async.done) {
|
||||
/* we're done, kill the ares handle */
|
||||
@@ -238,6 +239,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||
struct timeval *tvp, tv, store;
|
||||
long timediff;
|
||||
int itimeout;
|
||||
int timeout_ms;
|
||||
|
||||
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);
|
||||
|
||||
/* use the timeout period ares returned to us above */
|
||||
ares_waitperform(conn, (int)(tvp->tv_sec * 1000 + tvp->tv_usec/1000));
|
||||
/* use the timeout period ares returned to us above if less than one
|
||||
second is left, otherwise just use 1000ms to make sure the progress
|
||||
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)
|
||||
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 */
|
||||
timeout -= timediff?timediff:1; /* always deduct at least 1 */
|
||||
}
|
||||
if(timeout < 0) {
|
||||
/* our timeout, so we cancel the ares operation */
|
||||
ares_cancel(data->state.areschannel);
|
||||
@@ -270,14 +285,27 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||
if(!conn->async.dns) {
|
||||
/* a name was not resolved */
|
||||
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);
|
||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
}
|
||||
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,
|
||||
ares_strerror(conn->async.status));
|
||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
}
|
||||
else
|
||||
rc = CURLE_OPERATION_TIMEDOUT;
|
||||
|
||||
@@ -289,6 +317,31 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||
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
|
||||
@@ -310,7 +363,8 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
|
||||
struct in6_addr in6;
|
||||
#endif /* CURLRES_IPV6 */
|
||||
*waitp = FALSE;
|
||||
|
||||
*waitp = 0; /* default to synchronous response */
|
||||
|
||||
/* First check if this is an IPv4 address string */
|
||||
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 */
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
@@ -72,38 +72,27 @@
|
||||
* Only for builds using asynchronous name resolves
|
||||
**********************************************************************/
|
||||
#ifdef CURLRES_ASYNCH
|
||||
|
||||
/*
|
||||
* addrinfo_callback() gets called by ares, gethostbyname_thread() or
|
||||
* getaddrinfo_thread() when we got the name resolved (or not!).
|
||||
* Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
|
||||
* or getaddrinfo_thread() when we got the name resolved (or not!).
|
||||
*
|
||||
* If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the
|
||||
* address field since it might be freed when this function returns. This
|
||||
* operation stores the resolved data in the DNS cache.
|
||||
*
|
||||
* NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same
|
||||
* pointer it is given as argument!
|
||||
* If the status argument is CURL_ASYNC_SUCCESS, this function takes
|
||||
* ownership of the Curl_addrinfo passed, storing the resolved data
|
||||
* in 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,
|
||||
void *addr)
|
||||
struct Curl_addrinfo *ai)
|
||||
{
|
||||
struct connectdata *conn = (struct connectdata *)arg;
|
||||
struct Curl_dns_entry *dns = NULL;
|
||||
CURLcode rc = CURLE_OK;
|
||||
|
||||
conn->async.status = status;
|
||||
|
||||
if(CURL_ASYNC_SUCCESS == status) {
|
||||
|
||||
/*
|
||||
* IPv4/ares: Curl_addrinfo_copy() copies the address and returns an
|
||||
* allocated version.
|
||||
*
|
||||
* IPv6: Curl_addrinfo_copy() returns the input pointer!
|
||||
*/
|
||||
Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port);
|
||||
if(ai) {
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
@@ -138,35 +127,4 @@ static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */
|
||||
return rc;
|
||||
}
|
||||
|
||||
CURLcode Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
|
||||
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 */
|
||||
#endif /* CURLRES_ASYNCH */
|
||||
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -43,7 +43,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
@@ -76,8 +76,8 @@
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#if defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) \
|
||||
&& !defined(USE_ARES)
|
||||
#if defined(CURLRES_SYNCH) && \
|
||||
defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
|
||||
/* alarm-based timeouts can only be used with all the dependencies satisfied */
|
||||
#define USE_ALARM_TIMEOUT
|
||||
#endif
|
||||
@@ -189,12 +189,14 @@ Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
|
||||
case AF_INET:
|
||||
sa4 = (const void *)ai->ai_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
|
||||
case AF_INET6:
|
||||
sa6 = (const void *)ai->ai_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
|
||||
default:
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
#define __HOSTIP_H
|
||||
#ifndef HEADER_CURL_HOSTIP_H
|
||||
#define HEADER_CURL_HOSTIP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -37,51 +37,13 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup comfortable CURLRES_* defines to use in the host*.c sources.
|
||||
* Comfortable CURLRES_* definitions are included from setup.h
|
||||
*/
|
||||
|
||||
#ifdef USE_ARES
|
||||
#include <ares_version.h>
|
||||
#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
|
||||
* everything. OSF1 is known to require at least 8872 bytes. The buffer
|
||||
* 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);
|
||||
#endif
|
||||
|
||||
/* This is the callback function that is used when we build with asynch
|
||||
resolve, ipv4 */
|
||||
CURLcode Curl_addrinfo4_callback(void *arg,
|
||||
/* IPv4 threadsafe resolve function used for synch and asynch builds */
|
||||
Curl_addrinfo *Curl_ipv4_resolve_r(const char * hostname, int port);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
#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);
|
||||
|
||||
|
||||
/* Clone a Curl_addrinfo struct, works protocol independently */
|
||||
Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port);
|
||||
|
||||
/*
|
||||
* Curl_printable_address() returns a printable version of the 1st address
|
||||
* given in the 'ip' argument. The result will be stored in the buf that is
|
||||
@@ -263,4 +217,4 @@ void Curl_destroy_thread_data(struct Curl_async *async);
|
||||
extern sigjmp_buf curl_jmpenv;
|
||||
#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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -44,7 +44,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
@@ -87,8 +87,7 @@ bool Curl_ipvalid(struct SessionHandle *data)
|
||||
return TRUE; /* OK, proceed */
|
||||
}
|
||||
|
||||
#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
|
||||
|
||||
#ifdef CURLRES_SYNCH
|
||||
/*
|
||||
* Curl_getaddrinfo() - the ipv4 synchronous version.
|
||||
*
|
||||
@@ -110,7 +109,34 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
int port,
|
||||
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;
|
||||
#endif
|
||||
Curl_addrinfo *ai = NULL;
|
||||
@@ -118,17 +144,27 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
struct in_addr in;
|
||||
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)
|
||||
/* This is a dotted IP address 123.123.123.123-style */
|
||||
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.
|
||||
* Since there are three different versions of it, the following code is
|
||||
@@ -146,7 +182,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
* platforms.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_GETHOSTBYNAME_R_5
|
||||
#if defined(HAVE_GETHOSTBYNAME_R_5)
|
||||
/* Solaris, IRIX and more */
|
||||
h = gethostbyname_r(hostname,
|
||||
(struct hostent *)buf,
|
||||
@@ -164,8 +200,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
;
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_GETHOSTBYNAME_R_5 */
|
||||
#ifdef HAVE_GETHOSTBYNAME_R_6
|
||||
#elif defined(HAVE_GETHOSTBYNAME_R_6)
|
||||
/* Linux */
|
||||
|
||||
(void)gethostbyname_r(hostname,
|
||||
@@ -206,8 +241,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
*/
|
||||
|
||||
if(!h) /* failure */
|
||||
#endif/* HAVE_GETHOSTBYNAME_R_6 */
|
||||
#ifdef HAVE_GETHOSTBYNAME_R_3
|
||||
#elif defined(HAVE_GETHOSTBYNAME_R_3)
|
||||
/* AIX, Digital Unix/Tru64, HPUX 10, more? */
|
||||
|
||||
/* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
|
||||
@@ -259,26 +293,20 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
*/
|
||||
}
|
||||
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 */
|
||||
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
|
||||
* which the gethostbyname() is the preferred() function.
|
||||
* Here is code for platforms that don't have a thread safe
|
||||
* getaddrinfo() nor gethostbyname_r() function or for which
|
||||
* gethostbyname() is the preferred one.
|
||||
*/
|
||||
else {
|
||||
#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
|
||||
h = gethostbyname((char*)hostname);
|
||||
#else
|
||||
h = gethostbyname(hostname);
|
||||
#endif
|
||||
if(!h)
|
||||
infof(conn->data, "gethostbyname(2) failed for %s\n", hostname);
|
||||
#endif /*HAVE_GETHOSTBYNAME_R */
|
||||
h = gethostbyname((void*)hostname);
|
||||
#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
|
||||
}
|
||||
|
||||
if(h) {
|
||||
@@ -290,7 +318,3 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -43,7 +43,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
@@ -75,20 +75,6 @@
|
||||
**********************************************************************/
|
||||
#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)
|
||||
/* 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,
|
||||
serv, servlen,
|
||||
flags);
|
||||
if(0 == res) {
|
||||
if(0 == res)
|
||||
/* success */
|
||||
if(logfile)
|
||||
fprintf(logfile, "GETNAME %s:%d getnameinfo()\n",
|
||||
curl_memlog("GETNAME %s:%d getnameinfo()\n",
|
||||
source, line);
|
||||
}
|
||||
else {
|
||||
if(logfile)
|
||||
fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n",
|
||||
else
|
||||
curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
|
||||
source, line, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
|
||||
@@ -144,7 +126,7 @@ bool Curl_ipvalid(struct SessionHandle *data)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES)
|
||||
#if defined(CURLRES_SYNCH)
|
||||
|
||||
#ifdef DEBUG_ADDRINFO
|
||||
static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
|
||||
@@ -188,7 +170,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
int pf;
|
||||
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.
|
||||
@@ -252,6 +234,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */
|
||||
#endif /* ipv6 */
|
||||
#endif /* CURLRES_SYNCH */
|
||||
#endif /* CURLRES_IPV6 */
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
647
lib/hostthre.c
647
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -44,14 +44,20 @@
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for the close() proto */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PROCESS_H
|
||||
#include <process.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
|
||||
|
||||
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
|
||||
@@ -68,22 +74,18 @@
|
||||
#include "url.h"
|
||||
#include "multiif.h"
|
||||
#include "inet_pton.h"
|
||||
#include "inet_ntop.h"
|
||||
#include "curl_threads.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include "inet_ntop.h"
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX)
|
||||
#pragma message ("No _beginthreadex() available in this RTL")
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* Only for Windows threaded name resolves builds
|
||||
* Only for threaded name resolves builds
|
||||
**********************************************************************/
|
||||
#ifdef CURLRES_THREADED
|
||||
|
||||
@@ -92,249 +94,162 @@ static bool init_resolve_thread(struct connectdata *conn,
|
||||
const char *hostname, int port,
|
||||
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 {
|
||||
HANDLE thread_hnd;
|
||||
unsigned thread_id;
|
||||
DWORD thread_status;
|
||||
curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */
|
||||
HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */
|
||||
HANDLE event_resolved; /* marks that the thread obtained the information */
|
||||
HANDLE event_thread_started; /* marks that the thread has initialized and
|
||||
started */
|
||||
HANDLE mutex_terminate; /* serializes access to flag_terminate */
|
||||
HANDLE event_terminate; /* flag for thread to terminate instead of calling
|
||||
callbacks */
|
||||
#ifdef CURLRES_IPV6
|
||||
/* Data for synchronization between resolver thread and its parent */
|
||||
struct thread_sync_data {
|
||||
curl_mutex_t * mtx;
|
||||
int done;
|
||||
|
||||
char * hostname; /* hostname to resolve, Curl_async.hostname
|
||||
duplicate */
|
||||
int port;
|
||||
int sock_error;
|
||||
Curl_addrinfo *res;
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo hints;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Data for synchronization between resolver thread and its parent */
|
||||
struct thread_sync_data {
|
||||
HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */
|
||||
HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
|
||||
HANDLE event_terminate; /* thread_data.event_terminate duplicate */
|
||||
char * hostname; /* hostname to resolve, Curl_async.hostname
|
||||
duplicate */
|
||||
struct thread_data {
|
||||
curl_thread_t thread_hnd;
|
||||
curl_socket_t dummy_sock;
|
||||
unsigned int poll_interval;
|
||||
int interval_end;
|
||||
struct thread_sync_data tsd;
|
||||
};
|
||||
|
||||
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 */
|
||||
static
|
||||
void destroy_thread_sync_data(struct thread_sync_data * tsd)
|
||||
{
|
||||
if (tsd->mtx) {
|
||||
Curl_mutex_destroy(tsd->mtx);
|
||||
free(tsd->mtx);
|
||||
}
|
||||
|
||||
if(tsd->hostname)
|
||||
free(tsd->hostname);
|
||||
if(tsd->event_terminate)
|
||||
CloseHandle(tsd->event_terminate);
|
||||
if(tsd->mutex_terminate)
|
||||
CloseHandle(tsd->mutex_terminate);
|
||||
if(tsd->mutex_waiting)
|
||||
CloseHandle(tsd->mutex_waiting);
|
||||
|
||||
if (tsd->res)
|
||||
Curl_freeaddrinfo(tsd->res);
|
||||
|
||||
memset(tsd,0,sizeof(*tsd));
|
||||
}
|
||||
|
||||
/* Initialize resolver thread synchronization data */
|
||||
static
|
||||
BOOL init_thread_sync_data(struct thread_data * td,
|
||||
int init_thread_sync_data(struct thread_sync_data * tsd,
|
||||
const char * hostname,
|
||||
struct thread_sync_data * tsd)
|
||||
int port,
|
||||
const struct addrinfo *hints)
|
||||
{
|
||||
HANDLE curr_proc = GetCurrentProcess();
|
||||
|
||||
memset(tsd, 0, sizeof(*tsd));
|
||||
if(!DuplicateHandle(curr_proc, td->mutex_waiting,
|
||||
curr_proc, &tsd->mutex_waiting, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
/* failed to duplicate the mutex, no point in continuing */
|
||||
destroy_thread_sync_data(tsd);
|
||||
return FALSE;
|
||||
}
|
||||
if(!DuplicateHandle(curr_proc, td->mutex_terminate,
|
||||
curr_proc, &tsd->mutex_terminate, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
/* failed to duplicate the mutex, no point in continuing */
|
||||
destroy_thread_sync_data(tsd);
|
||||
return FALSE;
|
||||
}
|
||||
if(!DuplicateHandle(curr_proc, td->event_terminate,
|
||||
curr_proc, &tsd->event_terminate, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
/* failed to duplicate the event, no point in continuing */
|
||||
destroy_thread_sync_data(tsd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tsd->port = port;
|
||||
#ifdef CURLRES_IPV6
|
||||
DEBUGASSERT(hints);
|
||||
tsd->hints = *hints;
|
||||
#else
|
||||
(void) hints;
|
||||
#endif
|
||||
|
||||
tsd->mtx = malloc(sizeof(curl_mutex_t));
|
||||
if (tsd->mtx == NULL) goto err_exit;
|
||||
|
||||
Curl_mutex_init(tsd->mtx);
|
||||
|
||||
tsd->sock_error = CURL_ASYNC_SUCCESS;
|
||||
|
||||
/* Copying hostname string because original can be destroyed by parent
|
||||
* thread during gethostbyname execution.
|
||||
*/
|
||||
tsd->hostname = strdup(hostname);
|
||||
if(!tsd->hostname) {
|
||||
if (!tsd->hostname) goto err_exit;
|
||||
|
||||
return 1;
|
||||
|
||||
err_exit:
|
||||
/* Memory allocation failed */
|
||||
destroy_thread_sync_data(tsd);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* exits.
|
||||
* gethostbyname_thread() resolves a name and then 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
|
||||
* 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_data *td = (struct thread_data*) conn->async.os_specific;
|
||||
Curl_addrinfo *res;
|
||||
struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
|
||||
char service [NI_MAXSERV];
|
||||
int rc;
|
||||
struct addrinfo hints = td->hints;
|
||||
|
||||
/* Duplicate the passed mutex handle.
|
||||
* This allows us to use it even after the container gets destroyed
|
||||
* due to a resolver timeout.
|
||||
*/
|
||||
struct thread_sync_data tsd = { 0,0,0,NULL };
|
||||
snprintf(service, sizeof(service), "%d", tsd->port);
|
||||
|
||||
if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
|
||||
/* thread synchronization data initialization failed */
|
||||
return -1;
|
||||
rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
|
||||
|
||||
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 */
|
||||
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 */
|
||||
destroy_thread_sync_data(&tsd);
|
||||
|
||||
return (rc);
|
||||
/* An implicit _endthreadex() here */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
struct thread_data *td = (struct thread_data*) async->os_specific;
|
||||
curl_socket_t sock = td->dummy_sock;
|
||||
|
||||
if(td->mutex_terminate && td->event_terminate) {
|
||||
/* Signaling resolver thread to terminate */
|
||||
if(WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
|
||||
SetEvent(td->event_terminate);
|
||||
ReleaseMutex(td->mutex_terminate);
|
||||
}
|
||||
else {
|
||||
/* Something went wrong - just ignoring it */
|
||||
}
|
||||
}
|
||||
if (td->dummy_sock != CURL_SOCKET_BAD)
|
||||
sclose(td->dummy_sock);
|
||||
|
||||
if(td->mutex_terminate)
|
||||
CloseHandle(td->mutex_terminate);
|
||||
if(td->event_terminate)
|
||||
CloseHandle(td->event_terminate);
|
||||
if(td->event_thread_started)
|
||||
CloseHandle(td->event_thread_started);
|
||||
if (td->thread_hnd != curl_thread_t_null)
|
||||
Curl_thread_join(&td->thread_hnd);
|
||||
|
||||
if(sock != CURL_SOCKET_BAD)
|
||||
sclose(sock);
|
||||
|
||||
/* destroy the synchronization objects */
|
||||
if(td->mutex_waiting)
|
||||
CloseHandle(td->mutex_waiting);
|
||||
td->mutex_waiting = NULL;
|
||||
if(td->event_resolved)
|
||||
CloseHandle(td->event_resolved);
|
||||
|
||||
if(td->thread_hnd)
|
||||
CloseHandle(td->thread_hnd);
|
||||
destroy_thread_sync_data(&td->tsd);
|
||||
|
||||
free(async->os_specific);
|
||||
}
|
||||
@@ -397,114 +288,58 @@ static bool init_resolve_thread (struct connectdata *conn,
|
||||
const struct addrinfo *hints)
|
||||
{
|
||||
struct thread_data *td = calloc(1, sizeof(struct thread_data));
|
||||
HANDLE thread_and_event[2] = {0};
|
||||
int err = ENOMEM;
|
||||
|
||||
if(!td) {
|
||||
SET_ERRNO(ENOMEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Curl_safefree(conn->async.hostname);
|
||||
conn->async.hostname = strdup(hostname);
|
||||
if(!conn->async.hostname) {
|
||||
free(td);
|
||||
SET_ERRNO(ENOMEM);
|
||||
return FALSE;
|
||||
}
|
||||
conn->async.os_specific = (void*) td;
|
||||
if(!td)
|
||||
goto err_exit;
|
||||
|
||||
conn->async.port = port;
|
||||
conn->async.done = FALSE;
|
||||
conn->async.status = 0;
|
||||
conn->async.dns = NULL;
|
||||
conn->async.os_specific = (void*) td;
|
||||
td->dummy_sock = CURL_SOCKET_BAD;
|
||||
td->thread_hnd = curl_thread_t_null;
|
||||
|
||||
/* Create the mutex used to inform the resolver thread that we're
|
||||
* still waiting, and take initial ownership.
|
||||
*/
|
||||
td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
|
||||
if(td->mutex_waiting == NULL) {
|
||||
Curl_destroy_thread_data(&conn->async);
|
||||
SET_ERRNO(EAGAIN);
|
||||
return FALSE;
|
||||
}
|
||||
if (!init_thread_sync_data(&td->tsd, hostname, port, hints))
|
||||
goto err_exit;
|
||||
|
||||
/* Create the event that the thread uses to inform us that it's
|
||||
* done resolving. Do not signal it.
|
||||
*/
|
||||
td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if(td->event_resolved == NULL) {
|
||||
Curl_destroy_thread_data(&conn->async);
|
||||
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;
|
||||
}
|
||||
Curl_safefree(conn->async.hostname);
|
||||
conn->async.hostname = strdup(hostname);
|
||||
if(!conn->async.hostname)
|
||||
goto err_exit;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) THREAD_FUNC,
|
||||
conn, 0, &td->thread_id);
|
||||
#else
|
||||
td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
|
||||
conn, 0, &td->thread_id);
|
||||
#ifdef WIN32
|
||||
/* This socket is only to keep Curl_resolv_fdset() and select() happy;
|
||||
* should never become signalled for read since it's unbound but
|
||||
* Windows needs at least 1 socket in select().
|
||||
*/
|
||||
td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (td->dummy_sock == CURL_SOCKET_BAD)
|
||||
goto err_exit;
|
||||
#endif
|
||||
|
||||
#ifdef CURLRES_IPV6
|
||||
DEBUGASSERT(hints);
|
||||
td->hints = *hints;
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
|
||||
#else
|
||||
(void) hints;
|
||||
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
|
||||
#endif
|
||||
|
||||
if(!td->thread_hnd) {
|
||||
#ifndef _WIN32_WCE
|
||||
SET_ERRNO(errno);
|
||||
err = errno;
|
||||
#endif
|
||||
Curl_destroy_thread_data(&conn->async);
|
||||
return FALSE;
|
||||
goto err_exit;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
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 SessionHandle *data = conn->data;
|
||||
long timeout;
|
||||
DWORD status;
|
||||
CURLcode rc;
|
||||
CURLcode rc = CURLE_OK;
|
||||
|
||||
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 */
|
||||
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;
|
||||
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)
|
||||
*entry = conn->async.dns;
|
||||
|
||||
rc = CURLE_OK;
|
||||
|
||||
if(!conn->async.dns) {
|
||||
/* a name was not resolved */
|
||||
if(td->thread_status == CURLE_OUT_OF_MEMORY) {
|
||||
rc = CURLE_OUT_OF_MEMORY;
|
||||
failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
|
||||
}
|
||||
else if(conn->async.done) {
|
||||
if(conn->bits.httpproxy) {
|
||||
if (conn->bits.httpproxy) {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -618,19 +402,57 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
|
||||
struct Curl_dns_entry **entry)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
|
||||
int done = 0;
|
||||
|
||||
*entry = NULL;
|
||||
|
||||
if(conn->async.done) {
|
||||
/* we're done */
|
||||
if (!td) {
|
||||
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);
|
||||
|
||||
if(!conn->async.dns) {
|
||||
failf(data, "Could not resolve host: %s; %s",
|
||||
conn->host.name, Curl_strerror(conn, conn->async.status));
|
||||
return CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
*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;
|
||||
}
|
||||
|
||||
@@ -643,18 +465,18 @@ int Curl_resolv_getsock(struct connectdata *conn,
|
||||
|
||||
if(td && td->dummy_sock != CURL_SOCKET_BAD) {
|
||||
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 */
|
||||
socks[0] = td->dummy_sock;
|
||||
return GETSOCK_WRITESOCK(0);
|
||||
return GETSOCK_READSOCK(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,
|
||||
const char *hostname,
|
||||
@@ -665,7 +487,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
struct SessionHandle *data = conn->data;
|
||||
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)
|
||||
/* 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! */
|
||||
if(init_resolve_thread(conn, hostname, port, NULL)) {
|
||||
*waitp = TRUE; /* please wait for the response */
|
||||
*waitp = 1; /* expect asynchronous response */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fall-back to blocking version */
|
||||
infof(data, "init_resolve_thread() failed for %s; %s\n",
|
||||
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);
|
||||
return Curl_ipv4_resolve_r(hostname, 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,
|
||||
const char *hostname,
|
||||
@@ -704,11 +517,12 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
Curl_addrinfo *res;
|
||||
int error;
|
||||
char sbuf[NI_MAXSERV];
|
||||
int pf;
|
||||
int pf = PF_INET;
|
||||
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.
|
||||
*/
|
||||
@@ -741,6 +555,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
sclose(s);
|
||||
}
|
||||
}
|
||||
#endif /* !CURLRES_IPV4 */
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
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 */
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
#endif
|
||||
itoa(port, sbuf, 10);
|
||||
snprintf(sbuf, sizeof(sbuf), "%d", port);
|
||||
|
||||
/* fire up a new resolver thread! */
|
||||
if(init_resolve_thread(conn, hostname, port, &hints)) {
|
||||
*waitp = TRUE; /* please wait for the response */
|
||||
*waitp = 1; /* expect asynchronous response */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -768,5 +583,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif /* CURLRES_IPV6 */
|
||||
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
|
||||
#endif /* CURLRES_THREADED */
|
||||
|
||||
1157
lib/http.c
1157
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
|
||||
* 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 *content); /* content string to find */
|
||||
|
||||
char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader);
|
||||
|
||||
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 */
|
||||
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||
int tunnelsocket,
|
||||
@@ -87,5 +119,45 @@ int Curl_http_should_fail(struct connectdata *conn);
|
||||
#define TINY_INITIAL_POST_SIZE 1024
|
||||
#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
|
||||
|
||||
@@ -386,7 +386,7 @@ static void lm_resp(const unsigned char *keys,
|
||||
setup_des_key(keys+14, DESKEY(ks));
|
||||
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
|
||||
DESKEY(ks), DES_ENCRYPT);
|
||||
#elif USE_GNUTLS
|
||||
#elif defined(USE_GNUTLS)
|
||||
gcry_cipher_hd_t des;
|
||||
|
||||
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));
|
||||
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
|
||||
DESKEY(ks), DES_ENCRYPT);
|
||||
#elif USE_GNUTLS
|
||||
#elif defined(USE_GNUTLS)
|
||||
gcry_cipher_hd_t des;
|
||||
|
||||
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_Update(&MD4pw, pw, 2*len);
|
||||
MD4_Final(ntbuffer, &MD4pw);
|
||||
#elif USE_GNUTLS
|
||||
#elif defined(USE_GNUTLS)
|
||||
gcry_md_hd_t MD4pw;
|
||||
gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
|
||||
gcry_md_write(MD4pw, pw, 2*len);
|
||||
@@ -911,7 +911,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
MD5_CTX MD5pw;
|
||||
Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
|
||||
RAND_bytes(entropy,8);
|
||||
#elif USE_GNUTLS
|
||||
#elif defined(USE_GNUTLS)
|
||||
gcry_md_hd_t MD5pw;
|
||||
Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
|
||||
gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
|
||||
@@ -930,7 +930,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
|
||||
MD5_Init(&MD5pw);
|
||||
MD5_Update(&MD5pw, tmp, 16);
|
||||
MD5_Final(md5sum, &MD5pw);
|
||||
#elif USE_GNUTLS
|
||||
#elif defined(USE_GNUTLS)
|
||||
gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
|
||||
gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
|
||||
memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#ifdef HAVE_STROPTS_H
|
||||
# include <stropts.h>
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
# include <inet.h>
|
||||
#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 ) */
|
||||
if(Curl_raw_equal(conn->protostr, "LDAPS"))
|
||||
if(conn->protocol & PROT_SSL)
|
||||
ldap_ssl = 1;
|
||||
infof(data, "LDAP local: trying to establish %s connection\n",
|
||||
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);
|
||||
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);
|
||||
status = CURLE_COULDNT_CONNECT;
|
||||
goto quit;
|
||||
@@ -302,7 +302,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
|
||||
}
|
||||
server = ldap_init(conn->host.name, (int)conn->port);
|
||||
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);
|
||||
status = CURLE_COULDNT_CONNECT;
|
||||
goto quit;
|
||||
@@ -337,7 +337,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
|
||||
} else {
|
||||
server = ldap_init(conn->host.name, (int)conn->port);
|
||||
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);
|
||||
status = CURLE_COULDNT_CONNECT;
|
||||
goto quit;
|
||||
@@ -488,15 +488,15 @@ static void _ldap_trace (const char *fmt, ...)
|
||||
*/
|
||||
static int str2scope (const char *p)
|
||||
{
|
||||
if(!stricmp(p, "one"))
|
||||
if(strequal(p, "one"))
|
||||
return LDAP_SCOPE_ONELEVEL;
|
||||
if(!stricmp(p, "onetree"))
|
||||
if(strequal(p, "onetree"))
|
||||
return LDAP_SCOPE_ONELEVEL;
|
||||
if(!stricmp(p, "base"))
|
||||
if(strequal(p, "base"))
|
||||
return LDAP_SCOPE_BASE;
|
||||
if(!stricmp(p, "sub"))
|
||||
if(strequal(p, "sub"))
|
||||
return LDAP_SCOPE_SUBTREE;
|
||||
if(!stricmp( p, "subtree"))
|
||||
if(strequal( p, "subtree"))
|
||||
return LDAP_SCOPE_SUBTREE;
|
||||
return (-1);
|
||||
}
|
||||
@@ -582,7 +582,7 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
|
||||
if(!conn->data ||
|
||||
!conn->data->state.path ||
|
||||
conn->data->state.path[0] != '/' ||
|
||||
!checkprefix(conn->protostr, conn->data->change.url))
|
||||
!checkprefix("LDAP", conn->data->change.url))
|
||||
return LDAP_INVALID_SYNTAX;
|
||||
|
||||
ludp->lud_scope = LDAP_SCOPE_BASE;
|
||||
|
||||
@@ -10,17 +10,19 @@ ATCPSDKI= /GG/netinclude
|
||||
CC = m68k-amigaos-gcc
|
||||
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 \
|
||||
escape.c file.c formdata.c ftp.c getenv.c getinfo.c hash.c hostip.c \
|
||||
hostip4.c hostsyn.c http.c http_chunks.c http_digest.c \
|
||||
http_negotiate.c http_ntlm.c if2ip.c inet_ntop.c inet_pton.c krb4.c \
|
||||
ldap.c llist.c md5.c memdebug.c mprintf.c multi.c netrc.c parsedate.c \
|
||||
progress.c security.c select.c sendf.c share.c speedcheck.c ssluse.c \
|
||||
strequal.c strtok.c telnet.c timeval.c transfer.c url.c version.c \
|
||||
sslgen.c gtls.c strerror.c rawstr.c curl_addrinfo.c curl_rand.c \
|
||||
OBJS = amigaos.c \
|
||||
file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
|
||||
ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \
|
||||
netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \
|
||||
krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c \
|
||||
multi.c content_encoding.c share.c http_digest.c md5.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 \
|
||||
curl_memrchr.c
|
||||
|
||||
curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c
|
||||
|
||||
all: $(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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
@@ -104,12 +105,14 @@ static bool countcheck(const char *func, int line, const char *source)
|
||||
should not be made */
|
||||
if(memlimit && source) {
|
||||
if(!memsize) {
|
||||
if(logfile && source)
|
||||
fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
|
||||
if(source) {
|
||||
/* log to file */
|
||||
curl_memlog("LIMIT %s:%d %s reached memlimit\n",
|
||||
source, line, func);
|
||||
if(source)
|
||||
/* log to stderr also */
|
||||
fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
|
||||
source, line, func);
|
||||
}
|
||||
SET_ERRNO(ENOMEM);
|
||||
return TRUE; /* RETURN ERROR! */
|
||||
}
|
||||
@@ -117,8 +120,8 @@ static bool countcheck(const char *func, int line, const char *source)
|
||||
memsize--; /* countdown */
|
||||
|
||||
/* log the countdown */
|
||||
if(logfile && source)
|
||||
fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
|
||||
if(source)
|
||||
curl_memlog("LIMIT %s:%d %ld ALLOCS left\n",
|
||||
source, line, memsize);
|
||||
|
||||
}
|
||||
@@ -146,8 +149,8 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
|
||||
mem->size = wantedsize;
|
||||
}
|
||||
|
||||
if(logfile && source)
|
||||
fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n",
|
||||
if(source)
|
||||
curl_memlog("MEM %s:%d malloc(%zd) = %p\n",
|
||||
source, line, wantedsize, mem ? mem->mem : 0);
|
||||
return (mem ? mem->mem : NULL);
|
||||
}
|
||||
@@ -175,9 +178,9 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
|
||||
mem->size = user_size;
|
||||
}
|
||||
|
||||
if(logfile && source)
|
||||
fprintf(logfile, "MEM %s:%d calloc(%zu,%zu) = %p\n",
|
||||
source, line, wanted_elements, wanted_size, mem ? mem->mem : 0);
|
||||
if(source)
|
||||
curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
|
||||
source, line, wanted_elements, wanted_size, mem?mem->mem:0);
|
||||
return (mem ? mem->mem : NULL);
|
||||
}
|
||||
|
||||
@@ -197,8 +200,8 @@ char *curl_dostrdup(const char *str, int line, const char *source)
|
||||
if(mem)
|
||||
memcpy(mem, str, len);
|
||||
|
||||
if(logfile)
|
||||
fprintf(logfile, "MEM %s:%d strdup(%p) (%zu) = %p\n",
|
||||
if(source)
|
||||
curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
|
||||
source, line, str, len, 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 = (Curl_crealloc)(mem, size);
|
||||
if(logfile)
|
||||
fprintf(logfile, "MEM %s:%d realloc(%p, %zu) = %p\n",
|
||||
if(source)
|
||||
curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
|
||||
source, line, ptr, wantedsize, mem?mem->mem:NULL);
|
||||
|
||||
if(mem) {
|
||||
@@ -248,16 +251,16 @@ void curl_dofree(void *ptr, int line, const char *source)
|
||||
/* free for real */
|
||||
(Curl_cfree)(mem);
|
||||
|
||||
if(logfile)
|
||||
fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
|
||||
if(source)
|
||||
curl_memlog("MEM %s:%d free(%p)\n", source, line, ptr);
|
||||
}
|
||||
|
||||
int curl_socket(int domain, int type, int protocol, int line,
|
||||
const char *source)
|
||||
{
|
||||
int sockfd=socket(domain, type, protocol);
|
||||
if(logfile && (sockfd!=-1))
|
||||
fprintf(logfile, "FD %s:%d socket() = %d\n",
|
||||
if(source && (sockfd!=-1))
|
||||
curl_memlog("FD %s:%d socket() = %d\n",
|
||||
source, line, sockfd);
|
||||
return sockfd;
|
||||
}
|
||||
@@ -268,8 +271,8 @@ int curl_accept(int s, void *saddr, void *saddrlen,
|
||||
struct sockaddr *addr = (struct sockaddr *)saddr;
|
||||
curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
|
||||
int sockfd=accept(s, addr, addrlen);
|
||||
if(logfile)
|
||||
fprintf(logfile, "FD %s:%d accept() = %d\n",
|
||||
if(source)
|
||||
curl_memlog("FD %s:%d accept() = %d\n",
|
||||
source, line, 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 */
|
||||
void curl_mark_sclose(int sockfd, int line, const char *source)
|
||||
{
|
||||
if(logfile)
|
||||
fprintf(logfile, "FD %s:%d sclose(%d)\n",
|
||||
if(source)
|
||||
curl_memlog("FD %s:%d sclose(%d)\n",
|
||||
source, line, sockfd);
|
||||
}
|
||||
|
||||
@@ -294,8 +297,8 @@ FILE *curl_fopen(const char *file, const char *mode,
|
||||
int line, const char *source)
|
||||
{
|
||||
FILE *res=fopen(file, mode);
|
||||
if(logfile)
|
||||
fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
|
||||
if(source)
|
||||
curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
|
||||
source, line, file, mode, res);
|
||||
return res;
|
||||
}
|
||||
@@ -305,8 +308,8 @@ FILE *curl_fdopen(int filedes, const char *mode,
|
||||
int line, const char *source)
|
||||
{
|
||||
FILE *res=fdopen(filedes, mode);
|
||||
if(logfile)
|
||||
fprintf(logfile, "FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
|
||||
if(source)
|
||||
curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
|
||||
source, line, filedes, mode, res);
|
||||
return res;
|
||||
}
|
||||
@@ -319,9 +322,39 @@ int curl_fclose(FILE *file, int line, const char *source)
|
||||
assert(file != NULL);
|
||||
|
||||
res=fclose(file);
|
||||
if(logfile)
|
||||
fprintf(logfile, "FILE %s:%d fclose(%p)\n",
|
||||
if(source)
|
||||
curl_memlog("FILE %s:%d fclose(%p)\n",
|
||||
source, line, file);
|
||||
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 */
|
||||
|
||||
@@ -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
|
||||
* 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 void curl_memdebug(const char *logname);
|
||||
CURL_EXTERN void curl_memlimit(long limit);
|
||||
CURL_EXTERN void curl_memlog(const char *format, ...);
|
||||
|
||||
/* file descriptor manipulators */
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -1219,7 +1219,7 @@ int main()
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -181,7 +181,7 @@ struct Curl_multi {
|
||||
previous callback */
|
||||
};
|
||||
|
||||
static bool multi_conn_using(struct Curl_multi *multi,
|
||||
static struct connectdata *conn_using(struct Curl_multi *multi,
|
||||
struct SessionHandle *data);
|
||||
static void singlesocket(struct Curl_multi *multi,
|
||||
struct Curl_one_easy *easy);
|
||||
@@ -258,7 +258,6 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
||||
struct Curl_sh_entry {
|
||||
struct SessionHandle *easy;
|
||||
time_t timestamp;
|
||||
long inuse;
|
||||
int action; /* what action READ/WRITE this socket waits for */
|
||||
curl_socket_t socket; /* mainly to ease debugging */
|
||||
void *socketp; /* settable by users with curl_multi_assign() */
|
||||
@@ -568,7 +567,7 @@ static void debug_print_sock_hash(void *p)
|
||||
struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
|
||||
|
||||
fprintf(stderr, " [easy %p/magic %x/socket %d]",
|
||||
(void *)sh->easy, sh->easy->magic, sh->socket);
|
||||
(void *)sh->easy, sh->easy->magic, (int)sh->socket);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -577,6 +576,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
||||
{
|
||||
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||
struct Curl_one_easy *easy;
|
||||
struct connectdata *conn;
|
||||
|
||||
/* First, make some basic checks that the CURLM handle is a good handle */
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
connections in the shared connection cache, we might need to keep this
|
||||
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
|
||||
nice connection closures".
|
||||
*/
|
||||
if(multi_conn_using(multi, easy->easy_handle)) {
|
||||
/* There's at least one connection using this handle so we must keep
|
||||
this handle around. We also keep the connection cache pointer
|
||||
pointing to the shared one since that will be used on close as
|
||||
well. */
|
||||
if(conn) {
|
||||
if(conn->protocol & PROT_CLOSEACTION) {
|
||||
/* There's at least one CLOSEACTION connection using this handle so we
|
||||
must keep this handle around. We also keep the connection cache
|
||||
pointer pointing to the shared one since that will be used on close
|
||||
as well. */
|
||||
easy->easy_handle->state.shared_conn = multi;
|
||||
|
||||
/* this handle is still being used by a shared connection cache and
|
||||
thus we leave it around for now */
|
||||
add_closure(multi, easy->easy_handle);
|
||||
}
|
||||
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 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
|
||||
we're using gets cleaned up and we're left with nothing. */
|
||||
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);
|
||||
|
||||
if(easy->state != CURLM_STATE_COMPLETED) {
|
||||
@@ -1090,15 +1099,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
else
|
||||
#endif
|
||||
multistate(easy, CURLM_STATE_PROTOCONNECT);
|
||||
|
||||
}
|
||||
else {
|
||||
else
|
||||
/* after the connect has completed, go WAITDO or DO */
|
||||
multistate(easy, multi->pipelining_enabled?
|
||||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CURLM_STATE_PROTOCONNECT:
|
||||
@@ -1122,12 +1131,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
case CURLM_STATE_WAITDO:
|
||||
/* Wait for our turn to DO when we're pipelining requests */
|
||||
#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->send_pipe->size,
|
||||
easy->easy_conn->writechannel_inuse,
|
||||
easy->easy_conn->writechannel_inuse?1:0,
|
||||
isHandleAtHead(easy->easy_handle,
|
||||
easy->easy_conn->send_pipe));
|
||||
easy->easy_conn->send_pipe)?1:0);
|
||||
#endif
|
||||
if(!easy->easy_conn->writechannel_inuse &&
|
||||
isHandleAtHead(easy->easy_handle,
|
||||
@@ -1192,7 +1201,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
disconnect_conn = TRUE;
|
||||
}
|
||||
else
|
||||
retry = newurl?TRUE:FALSE;
|
||||
retry = (bool)(newurl?TRUE:FALSE);
|
||||
|
||||
Curl_posttransfer(easy->easy_handle);
|
||||
drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
|
||||
@@ -1310,12 +1319,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
}
|
||||
#ifdef DEBUGBUILD
|
||||
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->recv_pipe->size,
|
||||
easy->easy_conn->readchannel_inuse,
|
||||
easy->easy_conn->readchannel_inuse?1:0,
|
||||
isHandleAtHead(easy->easy_handle,
|
||||
easy->easy_conn->recv_pipe));
|
||||
easy->easy_conn->recv_pipe)?1:0);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@@ -1384,7 +1393,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
|
||||
easy->result = Curl_retry_request(easy->easy_conn, &newurl);
|
||||
if(!easy->result)
|
||||
retry = newurl?TRUE:FALSE;
|
||||
retry = (bool)(newurl?TRUE:FALSE);
|
||||
|
||||
/* call this even if the readwrite function returned error */
|
||||
Curl_posttransfer(easy->easy_handle);
|
||||
@@ -1559,17 +1568,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1588,7 +1586,10 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
while(easy != &multi->easy) {
|
||||
CURLMcode result;
|
||||
|
||||
do
|
||||
result = multi_runsingle(multi, easy);
|
||||
while (CURLM_CALL_MULTI_PERFORM == result);
|
||||
|
||||
if(result)
|
||||
returncode = result;
|
||||
|
||||
@@ -1750,7 +1751,6 @@ static void singlesocket(struct Curl_multi *multi,
|
||||
struct Curl_one_easy *easy_by_hash;
|
||||
bool remove_sock_from_hash;
|
||||
|
||||
memset(&socks, 0, sizeof(socks));
|
||||
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
|
||||
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 */
|
||||
data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;
|
||||
|
||||
do
|
||||
result = multi_runsingle(multi, data->set.one_easy);
|
||||
while (CURLM_CALL_MULTI_PERFORM == result);
|
||||
|
||||
if(data->set.one_easy->easy_conn)
|
||||
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 */
|
||||
if(data) {
|
||||
do
|
||||
result = multi_runsingle(multi, data->set.one_easy);
|
||||
while (CURLM_CALL_MULTI_PERFORM == result);
|
||||
|
||||
if(CURLM_OK >= result)
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static bool multi_conn_using(struct Curl_multi *multi,
|
||||
static struct connectdata *conn_using(struct Curl_multi *multi,
|
||||
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;
|
||||
|
||||
for(i=0; i< multi->connc->num; i++) {
|
||||
if(multi->connc->connects[i] &&
|
||||
(multi->connc->connects[i]->data == data) &&
|
||||
multi->connc->connects[i]->protocol & PROT_CLOSEACTION)
|
||||
return TRUE;
|
||||
(multi->connc->connects[i]->data == data))
|
||||
return multi->connc->connects[i];
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add the given data pointer to the list of 'closure handles' that are kept
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <unixlib.h>
|
||||
#endif
|
||||
|
||||
@@ -117,7 +117,7 @@ int Curl_parsenetrc(const char *host,
|
||||
struct passwd *pw;
|
||||
pw= getpwuid(geteuid());
|
||||
if(pw) {
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
home = decc_translate_vms(pw->pw_dir);
|
||||
#else
|
||||
home = pw->pw_dir;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#endif
|
||||
|
||||
@@ -990,7 +990,9 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
PRInt32 err;
|
||||
PRFileDesc *model = NULL;
|
||||
PRBool ssl2, ssl3, tlsv1;
|
||||
PRBool ssl2 = PR_FALSE;
|
||||
PRBool ssl3 = PR_FALSE;
|
||||
PRBool tlsv1 = PR_FALSE;
|
||||
struct SessionHandle *data = conn->data;
|
||||
curl_socket_t sockfd = conn->sock[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)
|
||||
goto error;
|
||||
|
||||
ssl2 = ssl3 = tlsv1 = PR_FALSE;
|
||||
|
||||
switch (data->set.ssl.version) {
|
||||
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
|
||||
* 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. */
|
||||
failf(data, "SSL_Destroy() returned error %d", SSL_Strerror(rc, NULL));
|
||||
failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex,
|
||||
}
|
||||
|
||||
/* An SSL error. */
|
||||
failf(conn->data, "SSL_Write() returned error %d",
|
||||
failf(conn->data, "SSL_Write() returned error %s",
|
||||
SSL_Strerror(rc, NULL));
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "sslgen.h"
|
||||
#include "ssh.h"
|
||||
#include "multiif.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
||||
#include <curl/mprintf.h>
|
||||
@@ -209,7 +210,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
|
||||
write_len = strlen(s);
|
||||
sptr = s;
|
||||
|
||||
while(1) {
|
||||
for(;;) {
|
||||
/* Write the buffer to the socket */
|
||||
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 */
|
||||
k->keepon |= KEEP_RECV_PAUSE;
|
||||
|
||||
DEBUGF(infof(data, "Pausing with %d bytes in buffer for type %02x\n",
|
||||
(int)len, type));
|
||||
DEBUGF(infof(data, "Pausing with %zu bytes in buffer for type %02x\n",
|
||||
len, type));
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@@ -425,7 +426,7 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
||||
return pausewrite(data, type, ptr, 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;
|
||||
}
|
||||
}
|
||||
@@ -510,7 +511,8 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
||||
|
||||
/* If session can pipeline, check connection buffer */
|
||||
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*/
|
||||
if(bytestocopy > 0) {
|
||||
@@ -527,7 +529,8 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
||||
buffertofill = conn->master_buffer;
|
||||
}
|
||||
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);
|
||||
buffertofill = buf;
|
||||
}
|
||||
|
||||
15
lib/sendf.h
15
lib/sendf.h
@@ -1,5 +1,5 @@
|
||||
#ifndef __SENDF_H
|
||||
#define __SENDF_H
|
||||
#ifndef HEADER_CURL_SENDF_H
|
||||
#define HEADER_CURL_SENDF_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
* 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 CLIENTWRITE_BODY 1
|
||||
#define CLIENTWRITE_HEADER 2
|
||||
#define CLIENTWRITE_BODY (1<<0)
|
||||
#define CLIENTWRITE_HEADER (1<<1)
|
||||
#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
|
||||
|
||||
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
|
||||
size_t len);
|
||||
|
||||
void Curl_read_rewind(struct connectdata *conn,
|
||||
size_t extraBytesRead);
|
||||
|
||||
/* internal read-function, does plain socket only */
|
||||
int Curl_read_plain(curl_socket_t sockfd,
|
||||
char *buf,
|
||||
@@ -86,4 +83,4 @@ int Curl_debug(struct SessionHandle *handle, curl_infotype type,
|
||||
struct connectdata *conn);
|
||||
|
||||
|
||||
#endif /* __SENDF_H */
|
||||
#endif /* HEADER_CURL_SENDF_H */
|
||||
|
||||
98
lib/setup.h
98
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -169,6 +169,15 @@
|
||||
# define CURL_DISABLE_TELNET
|
||||
# define CURL_DISABLE_DICT
|
||||
# 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
|
||||
|
||||
/* ================================================================ */
|
||||
@@ -326,7 +335,7 @@
|
||||
*/
|
||||
|
||||
#ifndef SIZEOF_OFF_T
|
||||
# if defined(__VMS) && (defined(__alpha) || defined(__ia64))
|
||||
# if defined(__VMS) && !defined(__VAX)
|
||||
# if defined(_LARGEFILE)
|
||||
# define SIZEOF_OFF_T 8
|
||||
# endif
|
||||
@@ -398,23 +407,68 @@
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
|
||||
!defined(__LCC__) /* lcc-win32 doesn't have _beginthreadex() */
|
||||
#ifdef ENABLE_IPV6
|
||||
#define USE_THREADING_GETADDRINFO
|
||||
#else
|
||||
#define USE_THREADING_GETHOSTBYNAME /* Cygwin uses alarm() function */
|
||||
#endif
|
||||
/*
|
||||
* 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_GETADDRINFO_THREADSAFE
|
||||
# undef HAVE_FREEADDRINFO
|
||||
# undef HAVE_GETADDRINFO
|
||||
# undef HAVE_GETNAMEINFO
|
||||
# undef ENABLE_IPV6
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where
|
||||
_beginthreadex() is not available */
|
||||
#if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES)
|
||||
#undef USE_THREADING_GETADDRINFO
|
||||
#undef USE_THREADING_GETHOSTBYNAME
|
||||
#define CURL_NO__BEGINTHREADEX
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* resolver specialty compile-time defines */
|
||||
/* CURLRES_* defines to use in the host*.c sources */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* lcc-win32 doesn't have _beginthreadex(), lacks threads support.
|
||||
*/
|
||||
|
||||
#if defined(__LCC__) && defined(WIN32)
|
||||
# undef USE_THREADS_POSIX
|
||||
# undef USE_THREADS_WIN32
|
||||
#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.
|
||||
*/
|
||||
@@ -435,20 +489,6 @@
|
||||
# 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.
|
||||
* 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()
|
||||
*/
|
||||
|
||||
#if defined(VMS) && \
|
||||
#if defined(__VMS) && \
|
||||
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
|
||||
#define getpwuid __32_getpwuid
|
||||
#endif
|
||||
@@ -432,7 +432,7 @@ typedef int sig_atomic_t;
|
||||
* Macro argv_item_t hides platform details to code using it.
|
||||
*/
|
||||
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#define argv_item_t __char_ptr32
|
||||
#else
|
||||
#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
|
||||
* 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;
|
||||
long conntime;
|
||||
*n = 0;
|
||||
do {
|
||||
for(;;) {
|
||||
tvnow = Curl_tvnow();
|
||||
/* calculating how long connection is establishing */
|
||||
conntime = Curl_tvdiff(tvnow, conn->created);
|
||||
@@ -104,7 +104,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
|
||||
buffersize -= nread;
|
||||
buf += nread;
|
||||
allread += nread;
|
||||
} while(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
|
||||
if(!socks5_resolve_local && hostname_len > 255)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#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
|
||||
* 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 */
|
||||
failf(data,
|
||||
"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_time);
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -66,7 +66,7 @@
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#endif
|
||||
@@ -264,9 +264,37 @@ static CURLcode sftp_libssh2_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;
|
||||
|
||||
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
|
||||
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 */
|
||||
@@ -459,10 +487,10 @@ static int sshkeycallback(CURL *easy,
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ssh_statemach_act() runs the SSH statemachine "one round" and returns. The
|
||||
* data the pointer 'block' points to will be set to TRUE if the libssh2
|
||||
* function returns LIBSSH2_ERROR_EAGAIN meaning it wants to be called again
|
||||
* when the socket is ready
|
||||
* ssh_statemach_act() runs the SSH state machine as far as it can without
|
||||
* blocking and without reaching the end. The data the pointer 'block' points
|
||||
* to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
|
||||
* meaning it wants to be called again when the socket is ready
|
||||
*/
|
||||
|
||||
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;
|
||||
*block = 0; /* we're not blocking by default */
|
||||
|
||||
do {
|
||||
|
||||
switch(sshc->state) {
|
||||
case SSH_S_STARTUP:
|
||||
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);
|
||||
result = sftp_libssh2_error_to_CURLE(err);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@@ -1429,9 +1460,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
sshc->actualcode = err>= LIBSSH2_FX_OK?
|
||||
sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
|
||||
if(!sshc->actualcode) {
|
||||
/* Sometimes, for some reason libssh2_sftp_last_error() returns zero
|
||||
even though libssh2_sftp_open() failed previously! We need to
|
||||
work around that! */
|
||||
/* Sometimes, for some reason libssh2_sftp_last_error() returns
|
||||
zero even though libssh2_sftp_open() failed previously! We need
|
||||
to work around that! */
|
||||
sshc->actualcode = CURLE_SSH;
|
||||
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) {
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
@@ -1508,8 +1540,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
sshc->actualcode = result;
|
||||
}
|
||||
else {
|
||||
/* store this original bitmask setup to use later on if we can't figure
|
||||
out a "real" bitmask */
|
||||
/* store this original bitmask setup to use later on if we can't
|
||||
figure out a "real" bitmask */
|
||||
sshc->orig_waitfor = data->req.keepon;
|
||||
|
||||
state(conn, SSH_STOP);
|
||||
@@ -1552,9 +1584,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
if(rc == -1) {
|
||||
unsigned int sftp_err = 0;
|
||||
/*
|
||||
* abort if failure wasn't that the dir already exists or the
|
||||
* permission was denied (creation might succeed further
|
||||
* down the path) - retry on unspecific FAILURE also
|
||||
* Abort if failure wasn't that the dir already exists or the
|
||||
* permission was denied (creation might succeed further down the
|
||||
* path) - retry on unspecific FAILURE also
|
||||
*/
|
||||
sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
|
||||
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:
|
||||
/*
|
||||
* This is a directory that we are trying to get, so produce a
|
||||
* directory listing
|
||||
* This is a directory that we are trying to get, so produce a directory
|
||||
* listing
|
||||
*/
|
||||
sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
|
||||
sftp_scp->path);
|
||||
@@ -1638,8 +1670,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
state(conn, SSH_STOP);
|
||||
break;
|
||||
}
|
||||
/* since this counts what we send to the client, we include the newline
|
||||
in this counter */
|
||||
/* since this counts what we send to the client, we include the
|
||||
newline in this counter */
|
||||
data->req.bytecount += sshc->readdir_len+1;
|
||||
|
||||
/* output debug output if that is requested */
|
||||
@@ -2236,6 +2268,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
|
||||
} while(!rc && (sshc->state != SSH_STOP));
|
||||
|
||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
/* we would block, we need to wait for the socket to be ready (in the
|
||||
right direction too)! */
|
||||
@@ -2458,7 +2492,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
|
||||
|
||||
#ifdef CURL_LIBSSH2_DEBUG
|
||||
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 */
|
||||
|
||||
state(conn, SSH_S_STARTUP);
|
||||
|
||||
122
lib/ssh.h
122
lib/ssh.h
@@ -23,6 +23,128 @@
|
||||
* $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
|
||||
|
||||
#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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -483,8 +483,7 @@ int cert_stuff(struct connectdata *conn,
|
||||
return 0;
|
||||
}
|
||||
if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) {
|
||||
failf(data, "cannot add certificate to client CA list",
|
||||
cert_file);
|
||||
failf(data, "cannot add certificate to client CA list");
|
||||
EVP_PKEY_free(pri);
|
||||
X509_free(x509);
|
||||
return 0;
|
||||
@@ -595,14 +594,14 @@ int cert_stuff(struct connectdata *conn,
|
||||
* the SSL context */
|
||||
if(!SSL_CTX_check_private_key(ctx)) {
|
||||
failf(data, "Private key does not match the certificate public key");
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
|
||||
/* erase it now */
|
||||
memset(global_passwd, 0, sizeof(global_passwd));
|
||||
#endif
|
||||
}
|
||||
return(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns non-zero on failure */
|
||||
@@ -659,7 +658,7 @@ static char *SSL_strerror(unsigned long error, char *buf, size_t size)
|
||||
(void) size;
|
||||
ERR_error_string(error, buf);
|
||||
#endif
|
||||
return (buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* USE_SSLEAY */
|
||||
@@ -709,7 +708,7 @@ void Curl_ossl_cleanup(void)
|
||||
/* EVP_cleanup() removes all ciphers and digests from the table. */
|
||||
EVP_cleanup();
|
||||
|
||||
#ifdef HAVE_ENGINE_cleanup
|
||||
#ifdef HAVE_ENGINE_CLEANUP
|
||||
ENGINE_cleanup();
|
||||
#endif
|
||||
|
||||
@@ -748,11 +747,22 @@ int Curl_ossl_check_cxn(struct connectdata *conn)
|
||||
CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
|
||||
{
|
||||
#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
|
||||
ENGINE *e = ENGINE_by_id(engine);
|
||||
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) {
|
||||
failf(data, "SSL Engine '%s' not found", engine);
|
||||
return (CURLE_SSL_ENGINE_NOTFOUND);
|
||||
return CURLE_SSL_ENGINE_NOTFOUND;
|
||||
}
|
||||
|
||||
if(data->state.engine) {
|
||||
@@ -766,14 +776,14 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
|
||||
ENGINE_free(e);
|
||||
failf(data, "Failed to initialise SSL Engine '%s':\n%s",
|
||||
engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
|
||||
return (CURLE_SSL_ENGINE_INITFAILED);
|
||||
return CURLE_SSL_ENGINE_INITFAILED;
|
||||
}
|
||||
data->state.engine = e;
|
||||
return (CURLE_OK);
|
||||
return CURLE_OK;
|
||||
#else
|
||||
(void)engine;
|
||||
failf(data, "SSL Engine not supported");
|
||||
return (CURLE_SSL_ENGINE_NOTFOUND);
|
||||
return CURLE_SSL_ENGINE_NOTFOUND;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -818,7 +828,7 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
|
||||
}
|
||||
#endif
|
||||
(void) data;
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -1735,7 +1745,7 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
|
||||
* the SO_ERROR is also lost.
|
||||
*/
|
||||
if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
|
||||
failf(data, "Unknown SSL protocol error in connection to %s:%d ",
|
||||
failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
|
||||
conn->host.name, conn->port);
|
||||
return rc;
|
||||
}
|
||||
@@ -2315,7 +2325,15 @@ ossl_connect_step3(struct connectdata *conn,
|
||||
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
|
||||
|
||||
@@ -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
|
||||
* 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:
|
||||
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:
|
||||
return "FTP: unknown PASS reply";
|
||||
|
||||
@@ -267,6 +270,12 @@ curl_easy_strerror(CURLcode error)
|
||||
case CURLE_AGAIN:
|
||||
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 */
|
||||
case CURLE_OBSOLETE4:
|
||||
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
|
||||
* 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))
|
||||
infof(data, "%s ", CURL_TELCMD(i));
|
||||
else
|
||||
infof(data, "%d ", i);
|
||||
infof(data, "%u ", i);
|
||||
if(CURL_TELOPT_OK(j))
|
||||
infof(data, "%s", CURL_TELOPT(j));
|
||||
else if(CURL_TELCMD_OK(j))
|
||||
@@ -1325,7 +1325,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
|
||||
switch(waitret) {
|
||||
case WAIT_TIMEOUT:
|
||||
{
|
||||
while(1) {
|
||||
for(;;) {
|
||||
if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
|
||||
keepon = FALSE;
|
||||
code = CURLE_READ_ERROR;
|
||||
|
||||
687
lib/tftp.c
687
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "connect.h"
|
||||
#include "strerror.h"
|
||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||
#include "multiif.h"
|
||||
#include "url.h"
|
||||
#include "rawstr.h"
|
||||
|
||||
@@ -103,7 +104,8 @@ typedef enum {
|
||||
} tftp_state_t;
|
||||
|
||||
typedef enum {
|
||||
TFTP_EVENT_INIT=0,
|
||||
TFTP_EVENT_NONE = -1,
|
||||
TFTP_EVENT_INIT = 0,
|
||||
TFTP_EVENT_RRQ = 1,
|
||||
TFTP_EVENT_WRQ = 2,
|
||||
TFTP_EVENT_DATA = 3,
|
||||
@@ -137,20 +139,22 @@ typedef struct tftp_state_data {
|
||||
tftp_state_t state;
|
||||
tftp_mode_t mode;
|
||||
tftp_error_t error;
|
||||
tftp_event_t event;
|
||||
struct connectdata *conn;
|
||||
curl_socket_t sockfd;
|
||||
int retries;
|
||||
time_t retry_time;
|
||||
time_t retry_max;
|
||||
int retry_time;
|
||||
int retry_max;
|
||||
time_t start_time;
|
||||
time_t max_time;
|
||||
time_t rx_time;
|
||||
unsigned short block;
|
||||
struct Curl_sockaddr_storage local_addr;
|
||||
struct Curl_sockaddr_storage remote_addr;
|
||||
curl_socklen_t remote_addrlen;
|
||||
ssize_t rbytes;
|
||||
size_t sbytes;
|
||||
size_t blksize;
|
||||
int rbytes;
|
||||
int sbytes;
|
||||
int blksize;
|
||||
int requested_blksize;
|
||||
tftp_packet_t rpacket;
|
||||
tftp_packet_t spacket;
|
||||
@@ -166,6 +170,11 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done);
|
||||
static CURLcode tftp_done(struct connectdata *conn,
|
||||
CURLcode, bool premature);
|
||||
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 */
|
||||
ZERO_NULL, /* do_more */
|
||||
tftp_connect, /* connect_it */
|
||||
ZERO_NULL, /* connecting */
|
||||
ZERO_NULL, /* doing */
|
||||
ZERO_NULL, /* proto_getsock */
|
||||
ZERO_NULL, /* doing_getsock */
|
||||
tftp_multi_statemach, /* connecting */
|
||||
tftp_doing, /* doing */
|
||||
tftp_getsock, /* proto_getsock */
|
||||
tftp_getsock, /* doing_getsock */
|
||||
ZERO_NULL, /* perform_getsock */
|
||||
tftp_disconnect, /* disconnect */
|
||||
PORT_TFTP, /* defport */
|
||||
PROT_TFTP /* protocol */
|
||||
};
|
||||
|
||||
|
||||
/**********************************************************
|
||||
*
|
||||
* tftp_set_timeouts -
|
||||
@@ -226,14 +234,14 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
||||
timeout = maxtime ;
|
||||
|
||||
/* Average restart after 5 seconds */
|
||||
state->retry_max = timeout/5;
|
||||
state->retry_max = (int)timeout/5;
|
||||
|
||||
if(state->retry_max < 1)
|
||||
/* avoid division by zero below */
|
||||
state->retry_max = 1;
|
||||
|
||||
/* 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)
|
||||
state->retry_time=1;
|
||||
|
||||
@@ -250,7 +258,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
||||
timeout = maxtime/10 ;
|
||||
|
||||
/* Average reposting an ACK after 15 seconds */
|
||||
state->retry_max = timeout/15;
|
||||
state->retry_max = (int)timeout/15;
|
||||
}
|
||||
/* But bound the total number */
|
||||
if(state->retry_max<3)
|
||||
@@ -265,10 +273,13 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
||||
state->retry_time=1;
|
||||
|
||||
infof(state->conn->data,
|
||||
"set timeouts for state %d; Total %d, retry %d maxtry %d\n",
|
||||
state->state, (state->max_time-state->start_time),
|
||||
"set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
|
||||
(int)state->state, (long)(state->max_time-state->start_time),
|
||||
state->retry_time, state->retry_max);
|
||||
|
||||
/* init RX time */
|
||||
time(&state->rx_time);
|
||||
|
||||
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);
|
||||
|
||||
if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
|
||||
int blksize;
|
||||
long blksize;
|
||||
|
||||
blksize = (int)strtol( value, NULL, 10 );
|
||||
blksize = strtol( value, NULL, 10 );
|
||||
|
||||
if(!blksize) {
|
||||
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
|
||||
* support for the server requesting a bigger blksize than the client
|
||||
* requests */
|
||||
failf(data, "%s (%d)",
|
||||
failf(data, "%s (%ld)",
|
||||
"server requested blksize larger than allocated", blksize);
|
||||
return CURLE_TFTP_ILLEGAL;
|
||||
}
|
||||
|
||||
state->blksize = blksize;
|
||||
state->blksize = (int)blksize;
|
||||
infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
|
||||
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;
|
||||
}
|
||||
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,
|
||||
char *buf, const char *option)
|
||||
{
|
||||
if( ( strlen(option) + csize + 1U ) > state->blksize )
|
||||
if( ( strlen(option) + csize + 1 ) > (size_t)state->blksize )
|
||||
return 0;
|
||||
strcpy(buf, option);
|
||||
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;
|
||||
#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);
|
||||
}
|
||||
|
||||
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;
|
||||
#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)
|
||||
{
|
||||
size_t sbytes;
|
||||
ssize_t senddata;
|
||||
const char *mode = "octet";
|
||||
char *filename;
|
||||
char buf[64];
|
||||
@@ -506,18 +520,19 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
|
||||
TFTP_OPTION_BLKSIZE);
|
||||
sbytes += tftp_option_add(state, sbytes,
|
||||
(char *)state->spacket.data+sbytes, buf );
|
||||
/* add timeout option */
|
||||
snprintf( buf, sizeof(buf), "%d", state->retry_time );
|
||||
/* add timeout option, this is the max time the session may live */
|
||||
snprintf( buf, sizeof(buf), "%d", state->retry_time*state->retry_max );
|
||||
sbytes += tftp_option_add(state, sbytes,
|
||||
(char *)state->spacket.data+sbytes,
|
||||
TFTP_OPTION_INTERVAL);
|
||||
sbytes += tftp_option_add(state, sbytes,
|
||||
(char *)state->spacket.data+sbytes, buf );
|
||||
|
||||
if (sendto(state->sockfd, (void *)state->spacket.data,
|
||||
senddata = sendto(state->sockfd, (void *)state->spacket.data,
|
||||
sbytes, 0,
|
||||
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));
|
||||
}
|
||||
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)
|
||||
{
|
||||
ssize_t sbytes;
|
||||
int rblock;
|
||||
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;
|
||||
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
|
||||
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,
|
||||
(struct sockaddr *)&state->remote_addr,
|
||||
state->remote_addrlen) < 0) {
|
||||
state->remote_addrlen);
|
||||
if(sbytes < 0) {
|
||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
@@ -599,6 +616,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
||||
else {
|
||||
state->state = TFTP_STATE_RX;
|
||||
}
|
||||
time(&state->rx_time);
|
||||
break;
|
||||
|
||||
case TFTP_EVENT_OACK:
|
||||
@@ -607,33 +625,38 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
||||
state->retries = 0;
|
||||
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
|
||||
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,
|
||||
(struct sockaddr *)&state->remote_addr,
|
||||
state->remote_addrlen) < 0) {
|
||||
state->remote_addrlen);
|
||||
if(sbytes < 0) {
|
||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
|
||||
/* we're ready to RX data */
|
||||
state->state = TFTP_STATE_RX;
|
||||
time(&state->rx_time);
|
||||
break;
|
||||
|
||||
case TFTP_EVENT_TIMEOUT:
|
||||
/* Increment the retry count and fail if over the limit */
|
||||
state->retries++;
|
||||
infof(data,
|
||||
"Timeout waiting for block %d ACK. Retries = %d\n", state->retries);
|
||||
"Timeout waiting for block %d ACK. Retries = %d\n",
|
||||
state->block+1, state->retries);
|
||||
if(state->retries > state->retry_max) {
|
||||
state->error = TFTP_ERR_TIMEOUT;
|
||||
state->state = TFTP_STATE_FIN;
|
||||
}
|
||||
else {
|
||||
/* Resend the previous ACK and check all sbytes were sent */
|
||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
||||
/* Resend the previous ACK */
|
||||
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||
4, SEND_4TH_ARG,
|
||||
(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));
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
@@ -641,6 +664,14 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
|
||||
break;
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
struct SessionHandle *data = state->conn->data;
|
||||
ssize_t sbytes;
|
||||
int rblock;
|
||||
int readcount;
|
||||
CURLcode res = CURLE_OK;
|
||||
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;
|
||||
}
|
||||
else {
|
||||
/* Re-send the data packet and check all sbytes were sent */
|
||||
if(sendto(state->sockfd, (void *)&state->spacket,
|
||||
/* Re-send the data packet */
|
||||
sbytes = sendto(state->sockfd, (void *)&state->spacket,
|
||||
4+state->sbytes, SEND_4TH_ARG,
|
||||
(struct sockaddr *)&state->remote_addr,
|
||||
state->remote_addrlen) < 0) {
|
||||
state->remote_addrlen);
|
||||
/* Check all sbytes were sent */
|
||||
if(sbytes<0) {
|
||||
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
|
||||
res = CURLE_SEND_ERROR;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/* fall-through */
|
||||
case TFTP_EVENT_OACK:
|
||||
/* This is the expected packet. Reset the counters and send the next
|
||||
block */
|
||||
time(&state->rx_time);
|
||||
state->block++;
|
||||
state->retries = 0;
|
||||
setpacketevent(&state->spacket, TFTP_EVENT_DATA);
|
||||
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;
|
||||
return CURLE_OK;
|
||||
}
|
||||
res = Curl_fillreadbuffer(state->conn, (int)state->blksize, &readcount);
|
||||
state->sbytes = readcount;
|
||||
res = Curl_fillreadbuffer(state->conn, (size_t)state->blksize,
|
||||
&state->sbytes);
|
||||
if(res)
|
||||
return res;
|
||||
/* Send the data packet and check all sbytes were sent */
|
||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
||||
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||
4+state->sbytes, SEND_4TH_ARG,
|
||||
(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));
|
||||
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 */
|
||||
state->retries++;
|
||||
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 */
|
||||
if(state->retries > state->retry_max) {
|
||||
state->error = TFTP_ERR_TIMEOUT;
|
||||
state->state = TFTP_STATE_FIN;
|
||||
}
|
||||
else {
|
||||
/* Re-send the data packet and check all sbytes were sent */
|
||||
if(sendto(state->sockfd, (void *)state->spacket.data,
|
||||
/* Re-send the data packet */
|
||||
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
|
||||
4+state->sbytes, SEND_4TH_ARG,
|
||||
(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));
|
||||
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:
|
||||
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;
|
||||
|
||||
default:
|
||||
@@ -761,6 +805,59 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
|
||||
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
|
||||
@@ -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
|
||||
* 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
|
||||
* bind() to better work with IPv6 or whatever size the struct could have,
|
||||
* but we learned that at least Tru64, AIX and IRIX *requires* the size of
|
||||
* that argument to match the exact size of a 'sockaddr_in' struct when
|
||||
* running IPv4-only.
|
||||
* We once used the size of the local_addr struct as the third argument
|
||||
* for bind() to better work with IPv6 or whatever size the struct could
|
||||
* have, but we learned that at least Tru64, AIX and IRIX *requires* the
|
||||
* size of that argument to match the exact size of a 'sockaddr_in' struct
|
||||
* when running IPv4-only.
|
||||
*
|
||||
* Therefore we use the size from the address we connected to, which we
|
||||
* assume uses the same IP version and thus hopefully this works for both
|
||||
@@ -920,38 +1017,341 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
|
||||
static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
|
||||
bool premature)
|
||||
{
|
||||
CURLcode code = CURLE_OK;
|
||||
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||
|
||||
(void)status; /* unused */
|
||||
(void)premature; /* not used */
|
||||
|
||||
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
|
||||
*
|
||||
* This callback handles the entire TFTP transfer
|
||||
* This callback initiates the TFTP transfer
|
||||
*
|
||||
**********************************************************/
|
||||
|
||||
static CURLcode tftp_do(struct connectdata *conn, bool *done)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
tftp_state_data_t *state;
|
||||
tftp_event_t event;
|
||||
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
|
||||
@@ -968,156 +1368,11 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
|
||||
}
|
||||
state = (tftp_state_data_t *)conn->proto.tftpc;
|
||||
|
||||
/* Run the TFTP State Machine */
|
||||
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;
|
||||
code = tftp_perform(conn, done);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user