summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/connect.c')
-rw-r--r--Utilities/cmcurl/lib/connect.c227
1 files changed, 135 insertions, 92 deletions
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index fb315fc..18ac32c 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, 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
@@ -56,15 +56,12 @@
#include <inet.h>
#endif
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
+#include "curl_printf.h"
#include "urldata.h"
#include "sendf.h"
#include "if2ip.h"
#include "strerror.h"
#include "connect.h"
-#include "curl_memory.h"
#include "select.h"
#include "url.h" /* for Curl_safefree() */
#include "multiif.h"
@@ -77,7 +74,8 @@
#include "conncache.h"
#include "multihandle.h"
-/* The last #include file should be: */
+/* The last #include files should be: */
+#include "curl_memory.h"
#include "memdebug.h"
#ifdef __SYMBIAN32__
@@ -238,7 +236,7 @@ long Curl_timeleft(struct SessionHandle *data,
}
static CURLcode bindlocal(struct connectdata *conn,
- curl_socket_t sockfd, int af)
+ curl_socket_t sockfd, int af, unsigned int scope)
{
struct SessionHandle *data = conn->data;
@@ -257,12 +255,6 @@ static CURLcode bindlocal(struct connectdata *conn,
int portnum = data->set.localportrange;
const char *dev = data->set.str[STRING_DEVICE];
int error;
- char myhost[256] = "";
- int done = 0; /* -1 for error, 1 for address found */
- bool is_interface = FALSE;
- bool is_host = FALSE;
- static const char *if_prefix = "if!";
- static const char *host_prefix = "host!";
/*************************************************************
* Select device to bind socket to
@@ -274,6 +266,13 @@ static CURLcode bindlocal(struct connectdata *conn,
memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
if(dev && (strlen(dev)<255) ) {
+ char myhost[256] = "";
+ int done = 0; /* -1 for error, 1 for address found */
+ bool is_interface = FALSE;
+ bool is_host = FALSE;
+ static const char *if_prefix = "if!";
+ static const char *host_prefix = "host!";
+
if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
dev += strlen(if_prefix);
is_interface = TRUE;
@@ -285,7 +284,8 @@ static CURLcode bindlocal(struct connectdata *conn,
/* interface */
if(!is_host) {
- switch(Curl_if2ip(af, conn->scope, dev, myhost, sizeof(myhost))) {
+ switch(Curl_if2ip(af, scope, conn->scope_id, dev,
+ myhost, sizeof(myhost))) {
case IF2IP_NOT_FOUND:
if(is_interface) {
/* Do not fall back to treating it as a host name */
@@ -374,7 +374,7 @@ static CURLcode bindlocal(struct connectdata *conn,
if(done > 0) {
#ifdef ENABLE_IPV6
- /* ipv6 address */
+ /* IPv6 address */
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
char *scope_ptr = strchr(myhost, '%');
@@ -397,7 +397,7 @@ static CURLcode bindlocal(struct connectdata *conn,
}
else
#endif
- /* ipv4 address */
+ /* IPv4 address */
if((af == AF_INET) &&
(Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
si4->sin_family = AF_INET;
@@ -540,7 +540,8 @@ static CURLcode trynextip(struct connectdata *conn,
int sockindex,
int tempindex)
{
- CURLcode rc = CURLE_COULDNT_CONNECT;
+ const int other = tempindex ^ 1;
+ CURLcode result = CURLE_COULDNT_CONNECT;
/* First clean up after the failed socket.
Don't close it yet to ensure that the next IP's socket gets a different
@@ -558,27 +559,29 @@ static CURLcode trynextip(struct connectdata *conn,
family = conn->tempaddr[tempindex]->ai_family;
ai = conn->tempaddr[tempindex]->ai_next;
}
+#ifdef ENABLE_IPV6
else if(conn->tempaddr[0]) {
/* happy eyeballs - try the other protocol family */
int firstfamily = conn->tempaddr[0]->ai_family;
-#ifdef ENABLE_IPV6
family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET;
-#else
- family = firstfamily;
-#endif
ai = conn->tempaddr[0]->ai_next;
}
+#endif
while(ai) {
- while(ai && ai->ai_family != family)
- ai = ai->ai_next;
+ if(conn->tempaddr[other]) {
+ /* we can safely skip addresses of the other protocol family */
+ while(ai && ai->ai_family != family)
+ ai = ai->ai_next;
+ }
if(ai) {
- rc = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
- if(rc == CURLE_COULDNT_CONNECT) {
+ result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
+ if(result == CURLE_COULDNT_CONNECT) {
ai = ai->ai_next;
continue;
}
+
conn->tempaddr[tempindex] = ai;
}
break;
@@ -588,7 +591,7 @@ static CURLcode trynextip(struct connectdata *conn,
if(fd_to_close != CURL_SOCKET_BAD)
Curl_closesocket(conn, fd_to_close);
- return rc;
+ return result;
}
/* Copies connection info into the session handle to make it available
@@ -656,7 +659,6 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr,
connection */
void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
{
- int error;
curl_socklen_t len;
struct Curl_sockaddr_storage ssrem;
struct Curl_sockaddr_storage ssloc;
@@ -667,6 +669,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
return;
if(!conn->bits.reuse) {
+ int error;
len = sizeof(struct Curl_sockaddr_storage);
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
@@ -677,6 +680,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
}
len = sizeof(struct Curl_sockaddr_storage);
+ memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
@@ -716,11 +720,11 @@ CURLcode Curl_is_connected(struct connectdata *conn,
bool *connected)
{
struct SessionHandle *data = conn->data;
- CURLcode code = CURLE_OK;
+ CURLcode result = CURLE_OK;
long allow;
int error = 0;
struct timeval now;
- int result;
+ int rc;
int i;
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
@@ -745,6 +749,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
}
for(i=0; i<2; i++) {
+ const int other = i ^ 1;
if(conn->tempsock[i] == CURL_SOCKET_BAD)
continue;
@@ -756,9 +761,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
#endif
/* check socket for connect */
- result = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);
+ rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);
- if(result == 0) { /* no connection yet */
+ if(rc == 0) { /* no connection yet */
if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
infof(data, "After %ldms connect time, move on!\n",
conn->timeoutms_per_addr);
@@ -771,10 +776,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
trynextip(conn, sockindex, 1);
}
}
- else if(result == CURL_CSELECT_OUT) {
+ else if(rc == CURL_CSELECT_OUT) {
if(verifyconnect(conn->tempsock[i], &error)) {
/* we are connected with TCP, awesome! */
- int other = i ^ 1;
/* use this socket from now on */
conn->sock[sockindex] = conn->tempsock[i];
@@ -788,9 +792,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
}
/* see if we need to do any proxy magic first once we connected */
- code = Curl_connected_proxy(conn, sockindex);
- if(code)
- return code;
+ result = Curl_connected_proxy(conn, sockindex);
+ if(result)
+ return result;
conn->bits.tcpconnect[sockindex] = TRUE;
@@ -805,7 +809,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
else
infof(data, "Connection failed\n");
}
- else if(result & CURL_CSELECT_ERR)
+ else if(rc & CURL_CSELECT_ERR)
(void)verifyconnect(conn->tempsock[i], &error);
/*
@@ -813,10 +817,11 @@ CURLcode Curl_is_connected(struct connectdata *conn,
* address" for the given host. But first remember the latest error.
*/
if(error) {
- char ipaddress[MAX_IPADR_LEN];
data->state.os_errno = error;
SET_SOCKERRNO(error);
if(conn->tempaddr[i]) {
+ CURLcode status;
+ char ipaddress[MAX_IPADR_LEN];
Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
infof(data, "connect to %s port %ld failed: %s\n",
ipaddress, conn->port, Curl_strerror(conn, error));
@@ -824,21 +829,24 @@ CURLcode Curl_is_connected(struct connectdata *conn,
conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
allow : allow / 2;
- code = trynextip(conn, sockindex, i);
+ status = trynextip(conn, sockindex, i);
+ if(status != CURLE_COULDNT_CONNECT
+ || conn->tempsock[other] == CURL_SOCKET_BAD)
+ /* the last attempt failed and no other sockets remain open */
+ result = status;
}
}
}
- if(code) {
+ if(result) {
/* no more addresses to try */
/* if the first address family runs out of addresses to try before
the happy eyeball timeout, go ahead and try the next family now */
if(conn->tempaddr[1] == NULL) {
- int rc;
- rc = trynextip(conn, sockindex, 1);
- if(rc == CURLE_OK)
- return CURLE_OK;
+ result = trynextip(conn, sockindex, 1);
+ if(!result)
+ return result;
}
failf(data, "Failed to connect to %s port %ld: %s",
@@ -846,7 +854,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
conn->port, Curl_strerror(conn, error));
}
- return code;
+ return result;
}
static void tcpnodelay(struct connectdata *conn,
@@ -875,7 +883,7 @@ static void tcpnodelay(struct connectdata *conn,
infof(data, "Could not set TCP_NODELAY: %s\n",
Curl_strerror(conn, SOCKERRNO));
else
- infof(data,"TCP_NODELAY set\n");
+ infof(data, "TCP_NODELAY set\n");
#else
(void)conn;
(void)sockfd;
@@ -941,16 +949,21 @@ void Curl_sndbufset(curl_socket_t sockfd)
detectOsState = DETECT_OS_VISTA_OR_LATER;
}
#else
- ULONGLONG majorVersionMask;
+ ULONGLONG cm;
OSVERSIONINFOEX osver;
memset(&osver, 0, sizeof(osver));
osver.dwOSVersionInfoSize = sizeof(osver);
osver.dwMajorVersion = majorVersion;
- majorVersionMask = VerSetConditionMask(0, VER_MAJORVERSION,
- VER_GREATER_EQUAL);
- if(VerifyVersionInfo(&osver, VER_MAJORVERSION, majorVersionMask))
+ cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL);
+ cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+ cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
+
+ if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
+ cm))
detectOsState = DETECT_OS_VISTA_OR_LATER;
else
detectOsState = DETECT_OS_PREVISTA;
@@ -977,10 +990,9 @@ void Curl_sndbufset(curl_socket_t sockfd)
* singleipconnect() connects to the given IP only, and it may return without
* having connected.
*/
-static CURLcode
-singleipconnect(struct connectdata *conn,
- const Curl_addrinfo *ai,
- curl_socket_t *sockp)
+static CURLcode singleipconnect(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ curl_socket_t *sockp)
{
struct Curl_sockaddr_ex addr;
int rc;
@@ -988,14 +1000,15 @@ singleipconnect(struct connectdata *conn,
bool isconnected = FALSE;
struct SessionHandle *data = conn->data;
curl_socket_t sockfd;
- CURLcode res = CURLE_OK;
+ CURLcode result;
char ipaddress[MAX_IPADR_LEN];
long port;
+ bool is_tcp;
*sockp = CURL_SOCKET_BAD;
- res = Curl_socket(conn, ai, &addr, &sockfd);
- if(res)
+ result = Curl_socket(conn, ai, &addr, &sockfd);
+ if(result)
/* Failed to create the socket, but still return OK since we signal the
lack of socket as well. This allows the parent function to keep looping
over alternative addresses/socket families etc. */
@@ -1013,14 +1026,20 @@ singleipconnect(struct connectdata *conn,
}
infof(data, " Trying %s...\n", ipaddress);
- if(data->set.tcp_nodelay)
+#ifdef ENABLE_IPV6
+ is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
+ addr.socktype == SOCK_STREAM;
+#else
+ is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
+#endif
+ if(is_tcp && data->set.tcp_nodelay)
tcpnodelay(conn, sockfd);
nosigpipe(conn, sockfd);
Curl_sndbufset(sockfd);
- if(data->set.tcp_keepalive)
+ if(is_tcp && data->set.tcp_keepalive)
tcpkeepalive(data, sockfd);
if(data->set.fsockopt) {
@@ -1038,19 +1057,26 @@ singleipconnect(struct connectdata *conn,
}
/* possibly bind the local end to an IP, interface or port */
- res = bindlocal(conn, sockfd, addr.family);
- if(res) {
- Curl_closesocket(conn, sockfd); /* close socket and bail out */
- if(res == CURLE_UNSUPPORTED_PROTOCOL) {
- /* The address family is not supported on this interface.
- We can continue trying addresses */
- return CURLE_OK;
+ if(addr.family == AF_INET
+#ifdef ENABLE_IPV6
+ || addr.family == AF_INET6
+#endif
+ ) {
+ result = bindlocal(conn, sockfd, addr.family,
+ Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
+ if(result) {
+ Curl_closesocket(conn, sockfd); /* close socket and bail out */
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ /* The address family is not supported on this interface.
+ We can continue trying addresses */
+ return CURLE_COULDNT_CONNECT;
+ }
+ return result;
}
- return res;
}
/* set socket non-blocking */
- curlx_nonblock(sockfd, TRUE);
+ (void)curlx_nonblock(sockfd, TRUE);
conn->connecttime = Curl_tvnow();
if(conn->num_addr > 1)
@@ -1084,25 +1110,25 @@ singleipconnect(struct connectdata *conn,
case EAGAIN:
#endif
#endif
- res = CURLE_OK;
+ result = CURLE_OK;
break;
default:
/* unknown error, fallthrough and try another address! */
infof(data, "Immediate connect fail for %s: %s\n",
- ipaddress, Curl_strerror(conn,error));
+ ipaddress, Curl_strerror(conn, error));
data->state.os_errno = error;
/* connect failed */
Curl_closesocket(conn, sockfd);
- res = CURLE_COULDNT_CONNECT;
+ result = CURLE_COULDNT_CONNECT;
}
}
- if(!res)
+ if(!result)
*sockp = sockfd;
- return res;
+ return result;
}
/*
@@ -1116,7 +1142,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
{
struct SessionHandle *data = conn->data;
struct timeval before = Curl_tvnow();
- CURLcode res = CURLE_COULDNT_CONNECT;
+ CURLcode result = CURLE_COULDNT_CONNECT;
long timeout_ms = Curl_timeleft(data, &before, TRUE);
@@ -1139,14 +1165,17 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* start connecting to first IP */
while(conn->tempaddr[0]) {
- res = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
- if(res == CURLE_OK)
- break;
+ result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
+ if(!result)
+ break;
conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
}
- if(conn->tempsock[0] == CURL_SOCKET_BAD)
- return res;
+ if(conn->tempsock[0] == CURL_SOCKET_BAD) {
+ if(!result)
+ result = CURLE_COULDNT_CONNECT;
+ return result;
+ }
data->info.numconnects++; /* to track the number of connections made */
@@ -1181,15 +1210,20 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
DEBUGASSERT(data);
- /* this only works for an easy handle that has been used for
- curl_easy_perform()! */
- if(data->state.lastconnect && data->multi_easy) {
+ /* this works for an easy handle:
+ * - that has been used for curl_easy_perform()
+ * - that is associated with a multi handle, and whose connection
+ * was detached with CURLOPT_CONNECT_ONLY
+ */
+ if(data->state.lastconnect && (data->multi_easy || data->multi)) {
struct connectdata *c = data->state.lastconnect;
struct connfind find;
find.tofind = data->state.lastconnect;
find.found = FALSE;
- Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
+ Curl_conncache_foreach(data->multi_easy?
+ &data->multi_easy->conn_cache:
+ &data->multi->conn_cache, &find, conn_is_conn);
if(!find.found) {
data->state.lastconnect = NULL;
@@ -1240,15 +1274,18 @@ int Curl_closesocket(struct connectdata *conn,
accept, then we MUST NOT call the callback but clear the accepted
status */
conn->sock_accepted[SECONDARYSOCKET] = FALSE;
- else
+ else {
+ Curl_multi_closed(conn, sock);
return conn->fclosesocket(conn->closesocket_client, sock);
+ }
}
- sclose(sock);
if(conn)
/* tell the multi-socket code about this */
Curl_multi_closed(conn, sock);
+ sclose(sock);
+
return 0;
}
@@ -1312,9 +1349,9 @@ CURLcode Curl_socket(struct connectdata *conn,
return CURLE_COULDNT_CONNECT;
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
- if(conn->scope && (addr->family == AF_INET6)) {
+ if(conn->scope_id && (addr->family == AF_INET6)) {
struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
- sa6->sin6_scope_id = conn->scope;
+ sa6->sin6_scope_id = conn->scope_id;
}
#endif
@@ -1325,16 +1362,22 @@ CURLcode Curl_socket(struct connectdata *conn,
#ifdef CURLDEBUG
/*
* Curl_conncontrol() is used to set the conn->bits.close bit on or off. It
- * MUST be called with the connclose() or connclose() macros with a stated
+ * MUST be called with the connclose() or connkeep() macros with a stated
* reason. The reason is only shown in debug builds but helps to figure out
* decision paths when connections are or aren't re-used as expected.
*/
void Curl_conncontrol(struct connectdata *conn, bool closeit,
const char *reason)
{
- infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive",
- reason);
- conn->bits.close = closeit; /* the only place in the source code that should
- assign this bit */
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) reason;
+#endif
+ if(closeit != conn->bits.close) {
+ infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive",
+ reason);
+
+ conn->bits.close = closeit; /* the only place in the source code that
+ should assign this bit */
+ }
}
#endif