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.c144
1 files changed, 105 insertions, 39 deletions
diff --git a/libs/libcurl/src/cfilters.c b/libs/libcurl/src/cfilters.c
index f2aaa1e864..43a5e004eb 100644
--- a/libs/libcurl/src/cfilters.c
+++ b/libs/libcurl/src/cfilters.c
@@ -28,23 +28,20 @@
#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 "curlx/warnless.h"
+#include "curlx/strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
static void cf_cntrl_update_info(struct Curl_easy *data,
struct connectdata *conn);
@@ -201,11 +198,11 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
}
*done = FALSE;
- now = Curl_now();
+ now = curlx_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);
@@ -371,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;
}
@@ -408,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;
@@ -415,14 +415,17 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
DEBUGASSERT(data->conn);
cf = data->conn->cfilter[sockindex];
- DEBUGASSERT(cf);
if(!cf) {
*done = FALSE;
return CURLE_FAILED_INIT;
}
*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);
@@ -430,24 +433,75 @@ 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
* socket and ip related information. */
cf_cntrl_update_info(data, data->conn);
conn_report_connect_stats(data, data->conn);
- data->conn->keepalive = Curl_now();
+ data->conn->keepalive = curlx_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;
}
+bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
+{
+ return (conn->cfilter[sockindex] != NULL);
+}
+
bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
{
struct Curl_cfilter *cf;
@@ -494,13 +548,36 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_MULTIPLEX)
return TRUE;
- if(cf->cft->flags & CF_TYPE_IP_CONNECT
- || cf->cft->flags & CF_TYPE_SSL)
+ if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
return FALSE;
}
return FALSE;
}
+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 = conn->cfilter[FIRSTSOCKET];
+ for(; cf; cf = cf->next) {
+ if(cf->cft->flags & CF_TYPE_HTTP) {
+ int value = 0;
+ result = cf->cft->query(cf, data, CF_QUERY_HTTP_VERSION, &value, NULL);
+ if(!result && ((value < 0) || (value > 255)))
+ result = CURLE_FAILED_INIT;
+ else
+ v = (unsigned char)value;
+ break;
+ }
+ if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
+ break;
+ }
+ return (unsigned char)(result ? 0 : v);
+}
+
bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf;
@@ -553,14 +630,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);
}
}
@@ -702,7 +780,7 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
CURLcode result = CURLE_OK;
size_t i;
- for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+ for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
event, arg1, arg2);
if(!ignore_result && result)
@@ -711,18 +789,6 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
return result;
}
-void Curl_conn_ev_data_attach(struct connectdata *conn,
- struct Curl_easy *data)
-{
- cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
-}
-
-void Curl_conn_ev_data_detach(struct connectdata *conn,
- struct Curl_easy *data)
-{
- cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
-}
-
CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
{
return cf_cntrl_all(data->conn, data, FALSE,
@@ -874,14 +940,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(!curlx_str_number(&p, &altsize, write_len))
+ write_len = (size_t)altsize;
}
}
#endif