summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/cfilters.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/cfilters.c')
-rw-r--r--libs/libcurl/src/cfilters.c92
1 files changed, 74 insertions, 18 deletions
diff --git a/libs/libcurl/src/cfilters.c b/libs/libcurl/src/cfilters.c
index c7f3c2d88c..c2036f7092 100644
--- a/libs/libcurl/src/cfilters.c
+++ b/libs/libcurl/src/cfilters.c
@@ -28,13 +28,14 @@
#include "strerror.h"
#include "cfilters.h"
#include "connect.h"
-#include "url.h" /* for Curl_safefree() */
+#include "url.h"
#include "sendf.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "multiif.h"
#include "progress.h"
#include "select.h"
#include "warnless.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -199,9 +200,9 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
*done = FALSE;
now = Curl_now();
if(!Curl_shutdown_started(data, sockindex)) {
- DEBUGF(infof(data, "shutdown start on%s connection",
- sockindex ? " secondary" : ""));
- Curl_shutdown_start(data, sockindex, &now);
+ CURL_TRC_M(data, "shutdown start on%s connection",
+ sockindex ? " secondary" : "");
+ Curl_shutdown_start(data, sockindex, 0, &now);
}
else {
timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
@@ -367,10 +368,10 @@ bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
if(cf)
- return cf->cft->do_connect(cf, data, blocking, done);
+ return cf->cft->do_connect(cf, data, done);
return CURLE_FAILED_INIT;
}
@@ -404,6 +405,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
bool blocking,
bool *done)
{
+#define CF_CONN_NUM_POLLS_ON_STACK 5
+ struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
+ struct curl_pollfds cpfds;
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
@@ -418,7 +422,11 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
}
*done = cf->connected;
- if(!*done) {
+ if(*done)
+ return CURLE_OK;
+
+ Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
+ while(!*done) {
if(Curl_conn_needs_flush(data, sockindex)) {
DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
result = Curl_conn_flush(data, sockindex);
@@ -426,7 +434,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
return result;
}
- result = cf->cft->do_connect(cf, data, blocking, done);
+ result = cf->cft->do_connect(cf, data, done);
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
+ blocking, result, *done);
if(!result && *done) {
/* Now that the complete filter chain is connected, let all filters
* persist information at the connection. E.g. cf-socket sets the
@@ -435,12 +445,56 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
conn_report_connect_stats(data, data->conn);
data->conn->keepalive = Curl_now();
Curl_verboseconnect(data, data->conn, sockindex);
+ goto out;
}
else if(result) {
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
+ result);
conn_report_connect_stats(data, data->conn);
+ goto out;
+ }
+
+ if(!blocking)
+ goto out;
+ else {
+ /* check allowed time left */
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+ struct easy_pollset ps;
+ int rc;
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "connect timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
+ }
+
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
+ Curl_pollfds_reset(&cpfds);
+ memset(&ps, 0, sizeof(ps));
+ /* In general, we want to send after connect, wait on that. */
+ if(sockfd != CURL_SOCKET_BAD)
+ Curl_pollset_set_out_only(data, &ps, sockfd);
+ Curl_conn_adjust_pollset(data, data->conn, &ps);
+ result = Curl_pollfds_add_ps(&cpfds, &ps);
+ if(result)
+ goto out;
+
+ rc = Curl_poll(cpfds.pfds, cpfds.n,
+ CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
+ rc);
+ if(rc < 0) {
+ result = CURLE_COULDNT_CONNECT;
+ goto out;
+ }
+ /* continue iterating */
}
}
+out:
+ Curl_pollfds_cleanup(&cpfds);
return result;
}
@@ -496,13 +550,14 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
return FALSE;
}
-unsigned char Curl_conn_http_version(struct Curl_easy *data)
+unsigned char Curl_conn_http_version(struct Curl_easy *data,
+ struct connectdata *conn)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_UNKNOWN_OPTION;
unsigned char v = 0;
- cf = data->conn ? data->conn->cfilter[FIRSTSOCKET] : NULL;
+ cf = conn->cfilter[FIRSTSOCKET];
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_HTTP) {
int value = 0;
@@ -571,14 +626,15 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
}
void Curl_conn_adjust_pollset(struct Curl_easy *data,
- struct easy_pollset *ps)
+ struct connectdata *conn,
+ struct easy_pollset *ps)
{
int i;
DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
+ DEBUGASSERT(conn);
for(i = 0; i < 2; ++i) {
- Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
+ Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
}
}
@@ -880,14 +936,14 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
DEBUGASSERT(data->conn);
conn = data->conn;
#ifdef DEBUGBUILD
- {
+ if(write_len) {
/* Allow debug builds to override this logic to force short sends
*/
- char *p = getenv("CURL_SMALLSENDS");
+ const char *p = getenv("CURL_SMALLSENDS");
if(p) {
- size_t altsize = (size_t)strtoul(p, NULL, 10);
- if(altsize)
- write_len = CURLMIN(write_len, altsize);
+ curl_off_t altsize;
+ if(!Curl_str_number(&p, &altsize, write_len))
+ write_len = (size_t)altsize;
}
}
#endif