summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/connect.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-03-04 14:34:39 -0500
committerBrad King <brad.king@kitware.com>2020-03-04 14:34:39 -0500
commitd61c3bd50520ce0179f52a129d5c660aebad88ba (patch)
tree4476c31b8b03de36811d94b5d9282318e84784b2 /Utilities/cmcurl/lib/connect.c
parent84dc14a967b78431c95ed3203e5dd301b6897267 (diff)
parent735ea3001ae98636a4cb7caf15a40960c0da39a1 (diff)
downloadcmake-d61c3bd50520ce0179f52a129d5c660aebad88ba.tar.gz
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2020-03-04 (b8d13668)
Diffstat (limited to 'Utilities/cmcurl/lib/connect.c')
-rw-r--r--Utilities/cmcurl/lib/connect.c241
1 files changed, 184 insertions, 57 deletions
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index 002535b429..0a7475cb6a 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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
@@ -75,6 +75,8 @@
#include "conncache.h"
#include "multihandle.h"
#include "system_win32.h"
+#include "quic.h"
+#include "socks.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -165,7 +167,7 @@ tcpkeepalive(struct Curl_easy *data,
static CURLcode
singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai, /* start connecting to this */
- curl_socket_t *sock);
+ int sockindex); /* 0 or 1 among the temp ones */
/*
* Curl_timeleft() returns the amount of milliseconds left allowed for the
@@ -368,6 +370,11 @@ static CURLcode bindlocal(struct connectdata *conn,
infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
dev, af, myhost, h->addr->ai_family);
Curl_resolv_unlock(data, h);
+ if(af != h->addr->ai_family) {
+ /* bad IP version combo, signal the caller to try another address
+ family if available */
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
done = 1;
}
else {
@@ -590,7 +597,7 @@ static CURLcode trynextip(struct connectdata *conn,
}
if(ai) {
- result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
+ result = singleipconnect(conn, ai, tempindex);
if(result == CURLE_COULDNT_CONNECT) {
ai = ai->ai_next;
continue;
@@ -620,13 +627,10 @@ void Curl_persistconninfo(struct connectdata *conn)
conn->data->info.conn_local_port = conn->local_port;
}
-UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
- long *port);
-
/* retrieves ip address and port from a sockaddr structure.
note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
-UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
- long *port)
+bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
+ char *addr, long *port)
{
struct sockaddr_in *si = NULL;
#ifdef ENABLE_IPV6
@@ -634,6 +638,8 @@ UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
struct sockaddr_un *su = NULL;
+#else
+ (void)salen;
#endif
switch(sa->sa_family) {
@@ -659,8 +665,12 @@ UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
case AF_UNIX:
- su = (struct sockaddr_un*)sa;
- msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
+ if(salen > (curl_socklen_t)sizeof(sa_family_t)) {
+ su = (struct sockaddr_un*)sa;
+ msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
+ }
+ else
+ addr[0] = 0; /* socket with no name */
*port = 0;
return TRUE;
#endif
@@ -678,8 +688,8 @@ UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
connection */
void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
{
- if(conn->socktype == SOCK_DGRAM)
- /* there's no connection! */
+ if(conn->transport != TRNSPRT_TCP)
+ /* there's no TCP connection! */
return;
#if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME)
@@ -688,10 +698,11 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssrem;
struct Curl_sockaddr_storage ssloc;
- curl_socklen_t len;
+ curl_socklen_t plen;
+ curl_socklen_t slen;
#ifdef HAVE_GETPEERNAME
- len = sizeof(struct Curl_sockaddr_storage);
- if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
+ plen = sizeof(struct Curl_sockaddr_storage);
+ if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
int error = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
@@ -699,9 +710,9 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
}
#endif
#ifdef HAVE_GETSOCKNAME
- len = sizeof(struct Curl_sockaddr_storage);
+ slen = sizeof(struct Curl_sockaddr_storage);
memset(&ssloc, 0, sizeof(ssloc));
- if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
+ if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
int error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
@@ -709,8 +720,8 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
}
#endif
#ifdef HAVE_GETPEERNAME
- if(!getaddressinfo((struct sockaddr*)&ssrem,
- conn->primary_ip, &conn->primary_port)) {
+ if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
+ conn->primary_ip, &conn->primary_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
@@ -718,8 +729,8 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
#endif
#ifdef HAVE_GETSOCKNAME
- if(!getaddressinfo((struct sockaddr*)&ssloc,
- conn->local_ip, &conn->local_port)) {
+ if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
+ conn->local_ip, &conn->local_port)) {
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
@@ -734,6 +745,79 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
Curl_persistconninfo(conn);
}
+/* After a TCP connection to the proxy has been verified, this function does
+ the next magic steps. If 'done' isn't set TRUE, it is not done yet and
+ must be called again.
+
+ Note: this function's sub-functions call failf()
+
+*/
+static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ if(conn->bits.socksproxy) {
+#ifndef CURL_DISABLE_PROXY
+ /* for the secondary socket (FTP), use the "connect to host"
+ * but ignore the "connect to port" (use the secondary port)
+ */
+ const char * const host =
+ conn->bits.httpproxy ?
+ conn->http_proxy.host.name :
+ conn->bits.conn_to_host ?
+ conn->conn_to_host.name :
+ sockindex == SECONDARYSOCKET ?
+ conn->secondaryhostname : conn->host.name;
+ const int port =
+ conn->bits.httpproxy ? (int)conn->http_proxy.port :
+ sockindex == SECONDARYSOCKET ? conn->secondary_port :
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port;
+ switch(conn->socks_proxy.proxytype) {
+ case CURLPROXY_SOCKS5:
+ case CURLPROXY_SOCKS5_HOSTNAME:
+ result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
+ host, port, sockindex, conn, done);
+ break;
+
+ case CURLPROXY_SOCKS4:
+ case CURLPROXY_SOCKS4A:
+ result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
+ conn, done);
+ break;
+
+ default:
+ failf(conn->data, "unknown proxytype option given");
+ result = CURLE_COULDNT_CONNECT;
+ } /* switch proxytype */
+#else
+ (void)sockindex;
+#endif /* CURL_DISABLE_PROXY */
+ }
+ else
+ *done = TRUE; /* no SOCKS proxy, so consider us connected */
+
+ return result;
+}
+
+/*
+ * post_SOCKS() is called after a successful connect to the peer, which
+ * *could* be a SOCKS proxy
+ */
+static void post_SOCKS(struct connectdata *conn,
+ int sockindex,
+ bool *connected)
+{
+ conn->bits.tcpconnect[sockindex] = TRUE;
+
+ *connected = TRUE;
+ if(sockindex == FIRSTSOCKET)
+ Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */
+ Curl_updateconninfo(conn, conn->sock[sockindex]);
+ Curl_verboseconnect(conn);
+}
+
/*
* Curl_is_connected() checks if the socket has connected.
*/
@@ -771,11 +855,37 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
+ if(SOCKS_STATE(conn->cnnct.state)) {
+ /* still doing SOCKS */
+ result = connect_SOCKS(conn, sockindex, connected);
+ if(!result && *connected)
+ post_SOCKS(conn, sockindex, connected);
+ return result;
+ }
+
for(i = 0; i<2; i++) {
const int other = i ^ 1;
if(conn->tempsock[i] == CURL_SOCKET_BAD)
continue;
+#ifdef ENABLE_QUIC
+ if(conn->transport == TRNSPRT_QUIC) {
+ result = Curl_quic_is_connected(conn, i, connected);
+ if(result) {
+ error = SOCKERRNO;
+ goto error;
+ }
+ if(*connected) {
+ /* use this socket from now on */
+ conn->sock[sockindex] = conn->tempsock[i];
+ conn->ip_addr = conn->tempaddr[i];
+ conn->tempsock[i] = CURL_SOCKET_BAD;
+ connkeep(conn, "HTTP/3 default");
+ }
+ return result;
+ }
+#endif
+
#ifdef mpeix
/* Call this function once now, and ignore the results. We do this to
"clear" the error state on the socket so that we can later read it
@@ -789,8 +899,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
if(rc == 0) { /* no connection yet */
error = 0;
if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
- infof(data, "After %ldms connect time, move on!\n",
- conn->timeoutms_per_addr);
+ infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
+ "ms connect time, move on!\n", conn->timeoutms_per_addr);
error = ETIMEDOUT;
}
@@ -819,18 +929,13 @@ CURLcode Curl_is_connected(struct connectdata *conn,
conn->tempsock[other] = CURL_SOCKET_BAD;
}
- /* see if we need to do any proxy magic first once we connected */
- result = Curl_connected_proxy(conn, sockindex);
- if(result)
+ /* see if we need to kick off any SOCKS proxy magic once we
+ connected */
+ result = connect_SOCKS(conn, sockindex, connected);
+ if(result || !*connected)
return result;
- conn->bits.tcpconnect[sockindex] = TRUE;
-
- *connected = TRUE;
- if(sockindex == FIRSTSOCKET)
- Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
- Curl_updateconninfo(conn, conn->sock[sockindex]);
- Curl_verboseconnect(conn);
+ post_SOCKS(conn, sockindex, connected);
return CURLE_OK;
}
@@ -839,6 +944,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
else if(rc & CURL_CSELECT_ERR)
(void)verifyconnect(conn->tempsock[i], &error);
+#ifdef ENABLE_QUIC
+ error:
+#endif
/*
* The connection failed here, we should attempt to connect to the "next
* address" for the given host. But first remember the latest error.
@@ -848,19 +956,21 @@ CURLcode Curl_is_connected(struct connectdata *conn,
SET_SOCKERRNO(error);
if(conn->tempaddr[i]) {
CURLcode status;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
char ipaddress[MAX_IPADR_LEN];
char buffer[STRERROR_LEN];
Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
+#endif
infof(data, "connect to %s port %ld failed: %s\n",
ipaddress, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
- allow : allow / 2;
+ allow : allow / 2;
status = trynextip(conn, sockindex, i);
- if(status != CURLE_COULDNT_CONNECT
- || conn->tempsock[other] == CURL_SOCKET_BAD)
+ if((status != CURLE_COULDNT_CONNECT) ||
+ conn->tempsock[other] == CURL_SOCKET_BAD)
/* the last attempt failed and no other sockets remain open */
result = status;
}
@@ -892,6 +1002,14 @@ CURLcode Curl_is_connected(struct connectdata *conn,
failf(data, "Failed to connect to %s port %ld: %s",
hostname, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
+
+#ifdef WSAETIMEDOUT
+ if(WSAETIMEDOUT == data->state.os_errno)
+ result = CURLE_OPERATION_TIMEDOUT;
+#elif defined(ETIMEDOUT)
+ if(ETIMEDOUT == data->state.os_errno)
+ result = CURLE_OPERATION_TIMEDOUT;
+#endif
}
return result;
@@ -900,14 +1018,12 @@ CURLcode Curl_is_connected(struct connectdata *conn,
static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
{
#if defined(TCP_NODELAY)
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
- struct Curl_easy *data = conn->data;
-#endif
curl_socklen_t onoff = (curl_socklen_t) 1;
int level = IPPROTO_TCP;
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ struct Curl_easy *data = conn->data;
char buffer[STRERROR_LEN];
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+#else
(void) conn;
#endif
@@ -915,8 +1031,6 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
sizeof(onoff)) < 0)
infof(data, "Could not set TCP_NODELAY: %s\n",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
- else
- infof(data, "TCP_NODELAY set\n");
#else
(void)conn;
(void)sockfd;
@@ -999,7 +1113,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
*/
static CURLcode singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai,
- curl_socket_t *sockp)
+ int sockindex)
{
struct Curl_sockaddr_ex addr;
int rc = -1;
@@ -1015,7 +1129,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
int optval = 1;
#endif
char buffer[STRERROR_LEN];
-
+ curl_socket_t *sockp = &conn->tempsock[sockindex];
*sockp = CURL_SOCKET_BAD;
result = Curl_socket(conn, ai, &addr, &sockfd);
@@ -1026,8 +1140,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
return CURLE_OK;
/* store remote address and port used in this connection attempt */
- if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
- ipaddress, &port)) {
+ if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen,
+ ipaddress, &port)) {
/* malformed address or bug in inet_ntop, try next address */
failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
@@ -1094,8 +1208,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
if(conn->num_addr > 1)
Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
- /* Connect TCP sockets, bind UDP */
- if(!isconnected && (conn->socktype == SOCK_STREAM)) {
+ /* Connect TCP and QUIC sockets */
+ if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
if(conn->bits.tcp_fastopen) {
#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
# if defined(HAVE_BUILTIN_AVAILABLE)
@@ -1124,8 +1238,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
(void *)&optval, sizeof(optval)) < 0)
infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
- else
- infof(data, "TCP_FASTOPEN_CONNECT set\n");
rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
#elif defined(MSG_FASTOPEN) /* old Linux */
@@ -1141,6 +1253,16 @@ static CURLcode singleipconnect(struct connectdata *conn,
if(-1 == rc)
error = SOCKERRNO;
+#ifdef ENABLE_QUIC
+ else if(conn->transport == TRNSPRT_QUIC) {
+ /* pass in 'sockfd' separately since it hasn't been put into the
+ tempsock array at this point */
+ result = Curl_quic_connect(conn, sockfd, sockindex,
+ &addr.sa_addr, addr.addrlen);
+ if(result)
+ error = SOCKERRNO;
+ }
+#endif
}
else {
*sockp = sockfd;
@@ -1214,7 +1336,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* start connecting to first IP */
while(conn->tempaddr[0]) {
- result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
+ result = singleipconnect(conn, conn->tempaddr[0], 0);
if(!result)
break;
conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
@@ -1326,12 +1448,11 @@ int Curl_closesocket(struct connectdata *conn,
curl_socket_t sock)
{
if(conn && conn->fclosesocket) {
- if((sock == conn->sock[SECONDARYSOCKET]) &&
- conn->sock_accepted[SECONDARYSOCKET])
+ if((sock == conn->sock[SECONDARYSOCKET]) && conn->sock_accepted)
/* if this socket matches the second socket, and that was created with
accept, then we MUST NOT call the callback but clear the accepted
status */
- conn->sock_accepted[SECONDARYSOCKET] = FALSE;
+ conn->sock_accepted = FALSE;
else {
int rc;
Curl_multi_closed(conn->data, sock);
@@ -1381,8 +1502,9 @@ CURLcode Curl_socket(struct connectdata *conn,
*/
addr->family = ai->ai_family;
- addr->socktype = conn->socktype;
- addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
+ addr->socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM;
+ addr->protocol = conn->transport != TRNSPRT_TCP ? IPPROTO_UDP :
+ ai->ai_protocol;
addr->addrlen = ai->ai_addrlen;
if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
@@ -1413,6 +1535,11 @@ CURLcode Curl_socket(struct connectdata *conn,
/* no socket, no connection */
return CURLE_COULDNT_CONNECT;
+ if(conn->transport == TRNSPRT_QUIC) {
+ /* QUIC sockets need to be nonblocking */
+ (void)curlx_nonblock(*sockfd, TRUE);
+ }
+
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
if(conn->scope_id && (addr->family == AF_INET6)) {
struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;