447
664
* Set the absolute number of maximum simultaneous alive connection that
448
665
* libcurl is allowed to have.
451
long newconnects= va_arg(param, long);
452
struct connectdata **newptr;
455
if(newconnects < data->state.numconnects) {
456
/* Since this number is *decreased* from the existing number, we must
457
close the possibly open connections that live on the indexes that
458
are being removed! */
459
for(i=newconnects; i< data->state.numconnects; i++)
460
Curl_disconnect(data->state.connects[i]);
462
/* If the most recent connection is no longer valid, mark it invalid. */
463
if(data->state.lastconnect <= newconnects)
464
data->state.lastconnect = -1;
467
newptr= (struct connectdata **)
468
realloc(data->state.connects,
469
sizeof(struct connectdata *) * newconnects);
471
/* we closed a few connections in vain, but so what? */
472
return CURLE_OUT_OF_MEMORY;
474
/* nullify the newly added pointers */
475
for(i=data->state.numconnects; i<newconnects; i++) {
479
data->state.connects = newptr;
480
data->state.numconnects = newconnects;
483
/* zero makes NO cache at all */
484
if(data->state.connects)
485
free(data->state.connects);
486
data->state.connects = NULL;
487
data->state.numconnects = 0;
488
data->state.lastconnect = -1;
667
result = Curl_ch_connc(data, data->state.connc, va_arg(param, long));
492
669
case CURLOPT_FORBID_REUSE:
494
671
* When this transfer is done, it must not be left to be reused by a
495
672
* subsequent transfer but shall be closed immediately.
497
data->set.reuse_forbid = va_arg(param, long)?TRUE:FALSE;
674
data->set.reuse_forbid = (bool)(0 != va_arg(param, long));
499
676
case CURLOPT_FRESH_CONNECT:
501
678
* This transfer shall not use a previously cached connection but
502
679
* should be made with a fresh new connect!
504
data->set.reuse_fresh = va_arg(param, long)?TRUE:FALSE;
681
data->set.reuse_fresh = (bool)(0 != va_arg(param, long));
506
683
case CURLOPT_VERBOSE:
508
685
* Verbose means infof() calls that give a lot of information about
509
686
* the connection and transfer procedures as well as internal choices.
511
data->set.verbose = va_arg(param, long)?TRUE:FALSE;
688
data->set.verbose = (bool)(0 != va_arg(param, long));
513
690
case CURLOPT_HEADER:
515
692
* Set to include the header in the general data output stream.
517
data->set.include_header = va_arg(param, long)?TRUE:FALSE;
694
data->set.include_header = (bool)(0 != va_arg(param, long));
519
696
case CURLOPT_NOPROGRESS:
521
698
* Shut off the internal supported progress meter
523
data->set.hide_progress = va_arg(param, long)?TRUE:FALSE;
700
data->set.hide_progress = (bool)(0 != va_arg(param, long));
524
701
if(data->set.hide_progress)
525
702
data->progress.flags |= PGRS_HIDE;
1492
1674
* Enable or disable TCP_NODELAY, which will disable/enable the Nagle
1495
data->set.tcp_nodelay = (bool)va_arg(param, long);
1498
/*********** 3rd party transfer options ***********/
1499
case CURLOPT_SOURCE_URL:
1503
data->set.source_url = va_arg(param, char *);
1504
data->set.printhost = (data->set.source_url != NULL);
1507
case CURLOPT_SOURCE_USERPWD:
1509
* Use SOURCE USER[:PASSWORD]
1511
data->set.source_userpwd = va_arg(param, char *);
1514
case CURLOPT_SOURCE_QUOTE:
1516
* List of RAW FTP commands to use after a connect
1518
data->set.source_quote = va_arg(param, struct curl_slist *);
1521
case CURLOPT_SOURCE_PREQUOTE:
1523
* List of RAW FTP commands to use before a transfer on the source host
1525
data->set.source_prequote = va_arg(param, struct curl_slist *);
1528
case CURLOPT_SOURCE_POSTQUOTE:
1530
* List of RAW FTP commands to use after a transfer on the source host
1532
data->set.source_postquote = va_arg(param, struct curl_slist *);
1677
data->set.tcp_nodelay = (bool)(0 != va_arg(param, long));
1681
case CURLOPT_SOURCE_URL:
1682
case CURLOPT_SOURCE_USERPWD:
1683
case CURLOPT_SOURCE_QUOTE:
1684
case CURLOPT_SOURCE_PREQUOTE:
1685
case CURLOPT_SOURCE_POSTQUOTE:
1686
These former 3rd party transfer options are deprecated */
1535
1688
case CURLOPT_FTP_ACCOUNT:
1536
1689
data->set.ftp_account = va_arg(param, char *);
1539
1692
case CURLOPT_IGNORE_CONTENT_LENGTH:
1540
data->set.ignorecl = va_arg(param, long)?TRUE:FALSE;
1693
data->set.ignorecl = (bool)(0 != va_arg(param, long));
1543
1696
case CURLOPT_CONNECT_ONLY:
1545
1698
* No data transfer, set up connection and let application use the socket
1547
data->set.connect_only = va_arg(param, long)?TRUE:FALSE;
1700
data->set.connect_only = (bool)(0 != va_arg(param, long));
1550
1703
case CURLOPT_FTP_ALTERNATIVE_TO_USER:
1551
1704
data->set.ftp_alternative_to_user = va_arg(param, char *);
1707
case CURLOPT_SOCKOPTFUNCTION:
1709
* socket callback function: called after socket() but before connect()
1711
data->set.fsockopt = va_arg(param, curl_sockopt_callback);
1714
case CURLOPT_SOCKOPTDATA:
1716
* socket callback data pointer. Might be NULL.
1718
data->set.sockopt_client = va_arg(param, void *);
1721
case CURLOPT_SSL_SESSIONID_CACHE:
1722
data->set.ssl.sessionid = (bool)(0 != va_arg(param, long));
1725
case CURLOPT_SSH_AUTH_TYPES:
1726
data->set.ssh_auth_types = va_arg(param, long);
1729
case CURLOPT_SSH_PUBLIC_KEYFILE:
1731
* Use this file instead of the $HOME/.ssh/id_dsa.pub file
1733
data->set.ssh_public_key = va_arg(param, char *);
1736
case CURLOPT_SSH_PRIVATE_KEYFILE:
1738
* Use this file instead of the $HOME/.ssh/id_dsa file
1740
data->set.ssh_private_key = va_arg(param, char *);
1743
case CURLOPT_HTTP_TRANSFER_DECODING:
1745
* disable libcurl transfer encoding is used
1747
data->set.http_te_skip = (bool)(0 == va_arg(param, long));
1750
case CURLOPT_HTTP_CONTENT_DECODING:
1752
* raw data passed to the application when content encoding is used
1754
data->set.http_ce_skip = (bool)(0 == va_arg(param, long));
1555
1757
/* unknown tag and its companion, just ignore: */
1556
1758
result = CURLE_FAILED_INIT; /* correct this */
1687
1912
return ret_val;
1915
static bool IsPipeliningPossible(struct SessionHandle *handle)
1917
if (handle->multi && Curl_multi_canPipeline(handle->multi) &&
1918
(handle->set.httpreq == HTTPREQ_GET ||
1919
handle->set.httpreq == HTTPREQ_HEAD) &&
1920
handle->set.httpversion != CURL_HTTP_VERSION_1_0)
1926
static bool IsPipeliningEnabled(struct SessionHandle *handle)
1928
if (handle->multi && Curl_multi_canPipeline(handle->multi))
1934
void Curl_addHandleToPipeline(struct SessionHandle *data,
1935
struct curl_llist *pipe)
1938
if(!IsPipeliningPossible(data)) {
1939
/* when not pipelined, there MUST be no handle in the list already */
1941
infof(data, "PIPE when no PIPE supposed!\n");
1944
Curl_llist_insert_next(pipe, pipe->tail, data);
1948
int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
1949
struct curl_llist *pipe)
1951
struct curl_llist_element *curr;
1955
if (curr->ptr == handle) {
1956
Curl_llist_remove(pipe, curr, NULL);
1957
return 1; /* we removed a handle */
1965
#if 0 /* this code is saved here as it is useful for debugging purposes */
1966
static void Curl_printPipeline(struct curl_llist *pipe)
1968
struct curl_llist_element *curr;
1972
struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
1973
infof(data, "Handle in pipeline: %s\n", data->reqdata.path);
1979
bool Curl_isHandleAtHead(struct SessionHandle *handle,
1980
struct curl_llist *pipe)
1982
struct curl_llist_element *curr = pipe->head;
1984
return (bool)(curr->ptr == handle);
1990
static struct SessionHandle* gethandleathead(struct curl_llist *pipe)
1992
struct curl_llist_element *curr = pipe->head;
1994
return (struct SessionHandle *) curr->ptr;
2000
static void signalPipeClose(struct curl_llist *pipe)
2002
struct curl_llist_element *curr;
2006
struct curl_llist_element *next = curr->next;
2007
struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
2009
#ifdef CURLDEBUG /* debug-only code */
2010
if(data->magic != CURLEASY_MAGIC_NUMBER) {
2012
infof(data, "signalPipeClose() found BAAD easy handle\n");
2016
data->state.pipe_broke = TRUE;
2017
Curl_multi_handlePipeBreak(data);
2018
Curl_llist_remove(pipe, curr, NULL);
1691
2025
* Given one filled in connection struct (named needle), this function should
1692
* detect if there already is one that have all the significant details
2026
* detect if there already is one that has all the significant details
1693
2027
* exactly the same and thus should be used instead.
2029
* If there is a match, this function returns TRUE - and has marked the
2030
* connection as 'in-use'. It must later be called with ConnectionDone() to
2031
* return back to 'idle' (unused) state.
1696
2034
ConnectionExists(struct SessionHandle *data,
1854
2267
struct connectdata *conn)
1857
for(i=0; i< data->state.numconnects; i++) {
1858
if(!data->state.connects[i])
2270
for(i=0; i< data->state.connc->num; i++) {
2271
if(!data->state.connc->connects[i])
1861
if(i == data->state.numconnects) {
2274
if(i == data->state.connc->num) {
1862
2275
/* there was no room available, kill one */
1863
2276
i = ConnectionKillOne(data);
1864
infof(data, "Connection (#%d) was killed to make room\n", i);
2278
infof(data, "Connection (#%d) was killed to make room (holds %d)\n",
2279
i, data->state.connc->num);
2281
infof(data, "This connection did not fit in the connection cache\n");
2284
conn->connectindex = i; /* Make the child know where the pointer to this
2285
particular data is stored. But note that this -1
2286
if this is not within the cache and this is
2287
probably not checked for everywhere (yet). */
1868
/* only do this if a true index was returned, if -1 was returned there
2290
/* Only do this if a true index was returned, if -1 was returned there
1869
2291
is no room in the cache for an unknown reason and we cannot store
1871
data->state.connects[i] = conn; /* fill in this */
1872
conn->connectindex = i; /* make the child know where the pointer to this
1873
particular data is stored */
2294
TODO: make sure we really can work with more handles than positions in
2295
the cache, or possibly we should (allow to automatically) resize the
2296
connection cache when we add more easy handles to a multi handle!
2298
data->state.connc->connects[i] = conn; /* fill in this */
1879
* This function logs in to a SOCKS4 proxy and sends the specifics to the final
1880
* destination server.
1883
* http://socks.permeo.com/protocol/socks4.protocol
1886
* Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
1887
* Nonsupport "Identification Protocol (RFC1413)"
1889
static int handleSock4Proxy(const char *proxy_name, struct connectdata *conn)
1891
unsigned char socksreq[262]; /* room for SOCKS4 request incl. user id */
1894
curl_socket_t sock = conn->sock[FIRSTSOCKET];
1895
struct SessionHandle *data = conn->data;
1897
Curl_nonblock(sock, FALSE);
1900
* Compose socks4 request
1904
* +----+----+----+----+----+----+----+----+----+----+....+----+
1905
* | VN | CD | DSTPORT | DSTIP | USERID |NULL|
1906
* +----+----+----+----+----+----+----+----+----+----+....+----+
1907
* # of bytes: 1 1 2 4 variable 1
1910
socksreq[0] = 4; /* version (SOCKS4) */
1911
socksreq[1] = 1; /* connect */
1912
*((unsigned short*)&socksreq[2]) = htons(conn->remote_port);
1916
struct Curl_dns_entry *dns;
1917
Curl_addrinfo *hp=NULL;
1920
rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
1922
if(rc == CURLRESOLV_ERROR)
1925
if(rc == CURLRESOLV_PENDING)
1926
/* this requires that we're in "wait for resolve" state */
1927
rc = Curl_wait_for_resolv(conn, &dns);
1930
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
1931
* returns a Curl_addrinfo pointer that may not always look the same.
1937
unsigned short ip[4];
1938
Curl_printable_address(hp, buf, sizeof(buf));
1940
if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
1941
&ip[0], &ip[1], &ip[2], &ip[3])) {
1943
socksreq[4] = (unsigned char)ip[0];
1944
socksreq[5] = (unsigned char)ip[1];
1945
socksreq[6] = (unsigned char)ip[2];
1946
socksreq[7] = (unsigned char)ip[3];
1949
hp = NULL; /* fail! */
1951
Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */
1955
failf(conn->data, "Failed to resolve \"%s\" for SOCKS4 connect.",
1962
* This is currently not supporting "Identification Protocol (RFC1413)".
1964
socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
1966
strlcat((char*)socksreq + 8, proxy_name, sizeof(socksreq) - 8);
1974
int packetsize = 9 +
1975
(int)strlen((char*)socksreq + 8); /* size including NUL */
1978
code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
1979
if ((code != CURLE_OK) || (written != packetsize)) {
1980
failf(conn->data, "Failed to send SOCKS4 connect request.");
1984
packetsize = 8; /* receive data size */
1986
/* Receive response */
1987
result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
1988
if ((result != CURLE_OK) || (actualread != packetsize)) {
1989
failf(conn->data, "Failed to receive SOCKS4 connect request ack.");
1996
* +----+----+----+----+----+----+----+----+
1997
* | VN | CD | DSTPORT | DSTIP |
1998
* +----+----+----+----+----+----+----+----+
1999
* # of bytes: 1 1 2 4
2001
* VN is the version of the reply code and should be 0. CD is the result
2002
* code with one of the following values:
2004
* 90: request granted
2005
* 91: request rejected or failed
2006
* 92: request rejected because SOCKS server cannot connect to
2007
* identd on the client
2008
* 93: request rejected because the client program and identd
2009
* report different user-ids
2012
/* wrong version ? */
2013
if (socksreq[0] != 0) {
2015
"SOCKS4 reply has wrong version, version should be 4.");
2023
infof(data, "SOCKS4 request granted.\n");
2027
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
2028
", request rejected or failed.",
2029
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
2030
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
2031
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
2036
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
2037
", request rejected because SOCKS server cannot connect to "
2038
"identd on the client.",
2039
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
2040
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
2041
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
2046
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
2047
", request rejected because the client program and identd "
2048
"report different user-ids.",
2049
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
2050
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
2051
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
2056
"Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
2058
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
2059
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
2060
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
2066
Curl_nonblock(sock, TRUE);
2068
return 0; /* Proxy was successful! */
2072
* This function logs in to a SOCKS5 proxy and sends the specifics to the final
2073
* destination server.
2075
static int handleSock5Proxy(const char *proxy_name,
2076
const char *proxy_password,
2077
struct connectdata *conn)
2080
According to the RFC1928, section "6. Replies". This is what a SOCK5
2083
+----+-----+-------+------+----------+----------+
2084
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
2085
+----+-----+-------+------+----------+----------+
2086
| 1 | 1 | X'00' | 1 | Variable | 2 |
2087
+----+-----+-------+------+----------+----------+
2091
o VER protocol version: X'05'
2096
unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
2101
curl_socket_t sock = conn->sock[FIRSTSOCKET];
2103
Curl_nonblock(sock, FALSE);
2105
socksreq[0] = 5; /* version */
2106
socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
2107
socksreq[2] = 0; /* no authentication */
2108
socksreq[3] = 2; /* username/password */
2110
code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
2112
if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
2113
failf(conn->data, "Unable to send initial SOCKS5 request.");
2117
result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
2118
if ((result != CURLE_OK) || (actualread != 2)) {
2119
failf(conn->data, "Unable to receive initial SOCKS5 response.");
2123
if (socksreq[0] != 5) {
2124
failf(conn->data, "Received invalid version in initial SOCKS5 response.");
2127
if (socksreq[1] == 0) {
2128
/* Nothing to do, no authentication needed */
2131
else if (socksreq[1] == 2) {
2132
/* Needs user name and password */
2133
int userlen, pwlen, len;
2135
userlen = (int)strlen(proxy_name);
2136
pwlen = proxy_password?(int)strlen(proxy_password):0;
2138
/* username/password request looks like
2139
* +----+------+----------+------+----------+
2140
* |VER | ULEN | UNAME | PLEN | PASSWD |
2141
* +----+------+----------+------+----------+
2142
* | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
2143
* +----+------+----------+------+----------+
2146
socksreq[len++] = 1; /* username/pw subnegotiation version */
2147
socksreq[len++] = (char) userlen;
2148
memcpy(socksreq + len, proxy_name, (int) userlen);
2150
socksreq[len++] = (char) pwlen;
2151
memcpy(socksreq + len, proxy_password, (int) pwlen);
2154
code = Curl_write(conn, sock, (char *)socksreq, len, &written);
2155
if ((code != CURLE_OK) || (len != written)) {
2156
failf(conn->data, "Failed to send SOCKS5 sub-negotiation request.");
2160
result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
2161
if ((result != CURLE_OK) || (actualread != 2)) {
2162
failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response.");
2166
/* ignore the first (VER) byte */
2167
if (socksreq[1] != 0) { /* status */
2168
failf(conn->data, "User was rejected by the SOCKS5 server (%d %d).",
2169
socksreq[0], socksreq[1]);
2173
/* Everything is good so far, user was authenticated! */
2177
if (socksreq[1] == 1) {
2179
"SOCKS5 GSSAPI per-message authentication is not supported.");
2182
else if (socksreq[1] == 255) {
2183
if (!proxy_name || !*proxy_name) {
2185
"No authentication method was acceptable. (It is quite likely"
2186
" that the SOCKS5 server wanted a username/password, since none"
2187
" was supplied to the server on this connection.)");
2190
failf(conn->data, "No authentication method was acceptable.");
2196
"Undocumented SOCKS5 mode attempted to be used by server.");
2201
/* Authentication is complete, now specify destination to the proxy */
2202
socksreq[0] = 5; /* version (SOCKS5) */
2203
socksreq[1] = 1; /* connect */
2204
socksreq[2] = 0; /* must be zero */
2205
socksreq[3] = 1; /* IPv4 = 1 */
2208
struct Curl_dns_entry *dns;
2209
Curl_addrinfo *hp=NULL;
2210
int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
2212
if(rc == CURLRESOLV_ERROR)
2215
if(rc == CURLRESOLV_PENDING)
2216
/* this requires that we're in "wait for resolve" state */
2217
rc = Curl_wait_for_resolv(conn, &dns);
2220
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
2221
* returns a Curl_addrinfo pointer that may not always look the same.
2227
unsigned short ip[4];
2228
Curl_printable_address(hp, buf, sizeof(buf));
2230
if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
2231
&ip[0], &ip[1], &ip[2], &ip[3])) {
2232
socksreq[4] = (unsigned char)ip[0];
2233
socksreq[5] = (unsigned char)ip[1];
2234
socksreq[6] = (unsigned char)ip[2];
2235
socksreq[7] = (unsigned char)ip[3];
2238
hp = NULL; /* fail! */
2240
Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */
2243
failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
2249
*((unsigned short*)&socksreq[8]) = htons(conn->remote_port);
2252
const int packetsize = 10;
2254
code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
2255
if ((code != CURLE_OK) || (written != packetsize)) {
2256
failf(conn->data, "Failed to send SOCKS5 connect request.");
2260
result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
2261
if ((result != CURLE_OK) || (actualread != packetsize)) {
2262
failf(conn->data, "Failed to receive SOCKS5 connect request ack.");
2266
if (socksreq[0] != 5) { /* version */
2268
"SOCKS5 reply has wrong version, version should be 5.");
2271
if (socksreq[1] != 0) { /* Anything besides 0 is an error */
2273
"Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
2274
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
2275
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
2276
(unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
2282
Curl_nonblock(sock, TRUE);
2283
return 0; /* Proxy was successful! */
2286
static CURLcode ConnectPlease(struct connectdata *conn,
2305
static CURLcode ConnectPlease(struct SessionHandle *data,
2306
struct connectdata *conn,
2287
2307
struct Curl_dns_entry *hostaddr,
2288
2308
bool *connected)
2290
2310
CURLcode result;
2291
2311
Curl_addrinfo *addr;
2292
struct SessionHandle *data = conn->data;
2293
char *hostname = data->change.proxy?conn->proxy.name:conn->host.name;
2312
#ifndef CURL_DISABLE_VERBOSE_STRINGS
2313
char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name;
2295
infof(data, "About to connect() to %s%s port %d\n",
2296
data->change.proxy?"proxy ":"",
2297
hostname, conn->port);
2315
infof(data, "About to connect() to %s%s port %d (#%d)\n",
2316
conn->bits.proxy?"proxy ":"",
2317
hostname, conn->port, conn->connectindex);
2299
2320
/*************************************************************
2300
2321
* Connect to server/proxy
2538
2572
host->name = host->encalloc;
2542
(void)conn; /* never used */
2548
* CreateConnection() sets up a new connectdata struct, or re-uses an already
2549
* existing one, and resolves host name.
2551
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
2552
* response will be coming asynchronously. If *async is FALSE, the name is
2555
* @param data The sessionhandle pointer
2556
* @param in_connect is set to the next connection data pointer
2557
* @param addr is set to the new dns entry for this connection. If this
2558
* connection is re-used it will be NULL.
2559
* @param async is set TRUE/FALSE depending on the nature of this lookup
2561
* @see SetupConnection()
2579
* Parse URL and fill in the relevant members of the connection struct.
2564
static CURLcode CreateConnection(struct SessionHandle *data,
2565
struct connectdata **in_connect,
2566
struct Curl_dns_entry **addr,
2581
static CURLcode ParseURLAndFillConnection(struct SessionHandle *data,
2582
struct connectdata *conn)
2571
CURLcode result=CURLE_OK;
2572
struct connectdata *conn;
2573
struct connectdata *conn_temp = NULL;
2575
struct Curl_dns_entry *hostaddr;
2576
#if defined(HAVE_ALARM) && !defined(USE_ARES)
2577
unsigned int prev_alarm=0;
2580
char user[MAX_CURL_USER_LENGTH];
2581
char passwd[MAX_CURL_PASSWORD_LENGTH];
2587
#ifdef HAVE_SIGACTION
2588
struct sigaction keep_sigact; /* store the old struct here */
2589
bool keep_copysig=FALSE; /* did copy it? */
2592
void *keep_sigact; /* store the old handler here */
2593
#endif /* HAVE_SIGNAL */
2594
#endif /* HAVE_SIGACTION */
2595
#endif /* SIGALRM */
2596
#endif /* USE_ARES */
2598
*addr = NULL; /* nothing yet */
2601
/*************************************************************
2603
*************************************************************/
2605
if(!data->change.url)
2606
return CURLE_URL_MALFORMAT;
2608
/* First, split up the current URL in parts so that we can use the
2609
parts for checking against the already present connections. In order
2610
to not have to modify everything at once, we allocate a temporary
2611
connection data struct and fill in for comparison purposes. */
2613
conn = (struct connectdata *)calloc(sizeof(struct connectdata), 1);
2615
*in_connect = NULL; /* clear the pointer */
2616
return CURLE_OUT_OF_MEMORY;
2618
/* We must set the return variable as soon as possible, so that our
2619
parent can cleanup any possible allocs we may have done before
2623
/* and we setup a few fields in case we end up actually using this struct */
2624
conn->data = data; /* remember our daddy */
2625
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
2626
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
2627
conn->connectindex = -1; /* no index */
2628
conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
2629
(data->set.proxytype == CURLPROXY_HTTP))?
2630
TRUE:FALSE; /* http proxy or not */
2632
/* Default protocol-independent behavior doesn't support persistent
2633
connections, so we set this to force-close. Protocols that support
2634
this need to set this to FALSE in their "curl_do" functions. */
2635
conn->bits.close = TRUE;
2637
/* maxdownload must be -1 on init, as 0 is a valid value! */
2638
conn->maxdownload = -1; /* might have been used previously! */
2640
/* Store creation time to help future close decision making */
2641
conn->created = Curl_tvnow();
2643
conn->bits.use_range = data->set.set_range?TRUE:FALSE; /* range status */
2644
conn->range = data->set.set_range; /* clone the range setting */
2645
conn->resume_from = data->set.set_resume_from; /* inherit resume_from */
2647
conn->bits.user_passwd = data->set.userpwd?1:0;
2648
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
2649
conn->bits.no_body = data->set.opt_no_body;
2650
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
2651
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
2652
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
2654
/* This initing continues below, see the comment "Continue connectdata
2655
* initialization here" */
2657
/***********************************************************
2658
* We need to allocate memory to store the path in. We get the size of the
2659
* full URL to be sure, and we need to make it at least 256 bytes since
2660
* other parts of the code will rely on this fact
2661
***********************************************************/
2662
#define LEAST_PATH_ALLOC 256
2663
urllen=strlen(data->change.url);
2664
if(urllen < LEAST_PATH_ALLOC)
2665
urllen=LEAST_PATH_ALLOC;
2668
* We malloc() the buffers below urllen+2 to make room for to possibilities:
2669
* 1 - an extra terminating zero
2670
* 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
2673
conn->pathbuffer=(char *)malloc(urllen+2);
2674
if(NULL == conn->pathbuffer)
2675
return CURLE_OUT_OF_MEMORY; /* really bad error */
2676
conn->path = conn->pathbuffer;
2678
conn->host.rawalloc=(char *)malloc(urllen+2);
2679
if(NULL == conn->host.rawalloc)
2680
return CURLE_OUT_OF_MEMORY;
2681
conn->host.name = conn->host.rawalloc;
2682
conn->host.name[0] = 0;
2587
char *path = data->reqdata.path;
2684
2589
/*************************************************************
2685
2590
* Parse the URL.
2811
2710
size_t hostlen = strlen(tmp);
2812
size_t pathlen = strlen(conn->path);
2711
size_t pathlen = strlen(path);
2814
2713
/* move the existing path plus the zero byte forward, to make room for
2815
2714
the host-name part */
2816
memmove(conn->path+hostlen+1, conn->path, pathlen+1);
2715
memmove(path+hostlen+1, path, pathlen+1);
2818
2717
/* now copy the trailing host part in front of the existing path */
2819
memcpy(conn->path+1, tmp, hostlen);
2718
memcpy(path+1, tmp, hostlen);
2821
conn->path[0]='/'; /* prepend the missing slash */
2720
path[0]='/'; /* prepend the missing slash */
2823
2722
*tmp=0; /* now cut off the hostname at the ? */
2825
else if(!conn->path[0]) {
2826
2725
/* if there's no path set, use a single slash */
2827
strcpy(conn->path, "/");
2830
2729
/* If the URL is malformatted (missing a '/' after hostname before path) we
2831
2730
* insert a slash here. The only letter except '/' we accept to start a path
2834
if(conn->path[0] == '?') {
2733
if(path[0] == '?') {
2835
2734
/* We need this function to deal with overlapping memory areas. We know
2836
2735
that the memory area 'path' points to is 'urllen' bytes big and that
2837
2736
is bigger than the path. Use +1 to move the zero byte too. */
2838
memmove(&conn->path[1], conn->path, strlen(conn->path)+1);
2839
conn->path[0] = '/';
2737
memmove(&path[1], path, strlen(path)+1);
2843
2742
* So if the URL was A://B/C,
2844
2743
* conn->protostr is A
2845
2744
* conn->host.name is B
2745
* data->reqdata.path is /C
2751
static void llist_dtor(void *user, void *element)
2760
* CreateConnection() sets up a new connectdata struct, or re-uses an already
2761
* existing one, and resolves host name.
2763
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
2764
* response will be coming asynchronously. If *async is FALSE, the name is
2767
* @param data The sessionhandle pointer
2768
* @param in_connect is set to the next connection data pointer
2769
* @param addr is set to the new dns entry for this connection. If this
2770
* connection is re-used it will be NULL.
2771
* @param async is set TRUE/FALSE depending on the nature of this lookup
2773
* @see SetupConnection()
2775
* *NOTE* this function assigns the conn->data pointer!
2778
static CURLcode CreateConnection(struct SessionHandle *data,
2779
struct connectdata **in_connect,
2780
struct Curl_dns_entry **addr,
2785
CURLcode result=CURLE_OK;
2786
struct connectdata *conn;
2787
struct connectdata *conn_temp = NULL;
2789
struct Curl_dns_entry *hostaddr;
2790
#if defined(HAVE_ALARM) && !defined(USE_ARES)
2791
unsigned int prev_alarm=0;
2794
char user[MAX_CURL_USER_LENGTH];
2795
char passwd[MAX_CURL_PASSWORD_LENGTH];
2802
#ifdef HAVE_SIGACTION
2803
struct sigaction keep_sigact; /* store the old struct here */
2804
bool keep_copysig=FALSE; /* did copy it? */
2807
void (*keep_sigact)(int); /* store the old handler here */
2808
#endif /* HAVE_SIGNAL */
2809
#endif /* HAVE_SIGACTION */
2810
#endif /* SIGALRM */
2811
#endif /* USE_ARES */
2813
*addr = NULL; /* nothing yet */
2816
/*************************************************************
2818
*************************************************************/
2820
if(!data->change.url)
2821
return CURLE_URL_MALFORMAT;
2823
/* First, split up the current URL in parts so that we can use the
2824
parts for checking against the already present connections. In order
2825
to not have to modify everything at once, we allocate a temporary
2826
connection data struct and fill in for comparison purposes. */
2828
conn = (struct connectdata *)calloc(sizeof(struct connectdata), 1);
2830
*in_connect = NULL; /* clear the pointer */
2831
return CURLE_OUT_OF_MEMORY;
2833
/* We must set the return variable as soon as possible, so that our
2834
parent can cleanup any possible allocs we may have done before
2838
/* and we setup a few fields in case we end up actually using this struct */
2840
conn->data = data; /* Setup the association between this connection
2841
and the SessionHandle */
2843
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
2844
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
2845
conn->connectindex = -1; /* no index */
2847
conn->proxytype = data->set.proxytype; /* type */
2848
conn->bits.proxy = (bool)(data->set.proxy && *data->set.proxy);
2849
conn->bits.httpproxy = (bool)(conn->bits.proxy
2850
&& (conn->proxytype == CURLPROXY_HTTP));
2853
/* Default protocol-independent behavior doesn't support persistent
2854
connections, so we set this to force-close. Protocols that support
2855
this need to set this to FALSE in their "curl_do" functions. */
2856
conn->bits.close = TRUE;
2858
conn->readchannel_inuse = FALSE;
2859
conn->writechannel_inuse = FALSE;
2864
/* Initialize the pipeline lists */
2865
conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
2866
conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
2867
if (!conn->send_pipe || !conn->recv_pipe)
2868
return CURLE_OUT_OF_MEMORY;
2870
/* Store creation time to help future close decision making */
2871
conn->created = Curl_tvnow();
2874
data->reqdata.use_range = (bool)(NULL != data->set.set_range);
2876
data->reqdata.range = data->set.set_range; /* clone the range setting */
2877
data->reqdata.resume_from = data->set.set_resume_from;
2879
conn->bits.user_passwd = (bool)(NULL != data->set.userpwd);
2880
conn->bits.proxy_user_passwd = (bool)(NULL != data->set.proxyuserpwd);
2881
conn->bits.no_body = data->set.opt_no_body;
2882
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
2883
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
2884
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
2886
/* This initing continues below, see the comment "Continue connectdata
2887
* initialization here" */
2889
/***********************************************************
2890
* We need to allocate memory to store the path in. We get the size of the
2891
* full URL to be sure, and we need to make it at least 256 bytes since
2892
* other parts of the code will rely on this fact
2893
***********************************************************/
2894
#define LEAST_PATH_ALLOC 256
2895
urllen=strlen(data->change.url);
2896
if(urllen < LEAST_PATH_ALLOC)
2897
urllen=LEAST_PATH_ALLOC;
2899
if (!data->set.source_url /* 3rd party FTP */
2900
&& data->reqdata.pathbuffer) {
2901
/* Free the old buffer */
2902
free(data->reqdata.pathbuffer);
2906
* We malloc() the buffers below urllen+2 to make room for to possibilities:
2907
* 1 - an extra terminating zero
2908
* 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
2911
data->reqdata.pathbuffer=(char *)malloc(urllen+2);
2912
if(NULL == data->reqdata.pathbuffer)
2913
return CURLE_OUT_OF_MEMORY; /* really bad error */
2914
data->reqdata.path = data->reqdata.pathbuffer;
2916
conn->host.rawalloc=(char *)malloc(urllen+2);
2917
if(NULL == conn->host.rawalloc)
2918
return CURLE_OUT_OF_MEMORY;
2920
conn->host.name = conn->host.rawalloc;
2921
conn->host.name[0] = 0;
2923
result = ParseURLAndFillConnection(data, conn);
2924
if (result != CURLE_OK) {
2849
2928
/*************************************************************
2850
2929
* Take care of proxy authentication stuff