aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/http.c2
-rw-r--r--lib/http2.c13
-rw-r--r--lib/http2.h10
-rw-r--r--lib/multi.c35
-rw-r--r--lib/multihandle.h3
-rw-r--r--lib/multiif.h2
-rw-r--r--lib/url.c41
7 files changed, 94 insertions, 12 deletions
diff --git a/lib/http.c b/lib/http.c
index 28da5c47b..c3d72b759 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -176,6 +176,8 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
http->len = BUFSIZE;
http->memlen = 0;
+ Curl_http2_setup_conn(conn);
+
return CURLE_OK;
}
diff --git a/lib/http2.c b/lib/http2.c
index 7e58a7897..c6efc21c8 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -93,6 +93,13 @@ static CURLcode http2_disconnect(struct connectdata *conn,
return CURLE_OK;
}
+/* called from Curl_http_setup_conn */
+void Curl_http2_setup_conn(struct connectdata *conn)
+{
+ conn->proto.httpc.settings.max_concurrent_streams =
+ DEFAULT_MAX_CONCURRENT_STREAMS;
+}
+
/*
* HTTP2 handler interface. This isn't added to the general list of protocols
* but will be used at run-time when the protocol is dynamically switched from
@@ -302,6 +309,9 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
httpc->settings.max_concurrent_streams));
DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
httpc->settings.enable_push?"TRUE":"false"));
+ infof(conn->data,
+ "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
+ Curl_multi_connchanged(conn->data->multi);
break;
default:
DEBUGF(infof(conn->data, "Got frame type %x for stream %x!\n",
@@ -1198,6 +1208,9 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
conn->httpversion = 20;
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+ infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
+ Curl_multi_connchanged(conn->data->multi);
+
return CURLE_OK;
}
diff --git a/lib/http2.h b/lib/http2.h
index a2e4eb7c2..1614736d3 100644
--- a/lib/http2.h
+++ b/lib/http2.h
@@ -7,7 +7,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
@@ -26,6 +26,11 @@
#ifdef USE_NGHTTP2
#include "http.h"
+
+/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting
+ from the peer */
+#define DEFAULT_MAX_CONCURRENT_STREAMS 13
+
/*
* Store nghttp2 version info in this buffer, Prefix with a space. Return
* total length written.
@@ -39,12 +44,15 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
CURLcode Curl_http2_setup(struct connectdata *conn);
CURLcode Curl_http2_switched(struct connectdata *conn,
const char *data, size_t nread);
+/* called from Curl_http_setup_conn */
+void Curl_http2_setup_conn(struct connectdata *conn);
#else /* USE_NGHTTP2 */
#define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_setup_conn(x)
#endif
#endif /* HEADER_CURL_HTTP2_H */
diff --git a/lib/multi.c b/lib/multi.c
index c6bfe23c9..cff3b8d55 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -928,6 +928,34 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
return CURLM_OK;
}
+/*
+ * Curl_multi_connchanged() is called to tell that there is a connection in
+ * this multi handle that has changed state (pipelining become possible, the
+ * number of allowed streams changed or similar), and a subsequent use of this
+ * multi handle should move CONNECT_PEND handles back to CONNECT to have them
+ * retry.
+ */
+void Curl_multi_connchanged(struct Curl_multi *multi)
+{
+ multi->recheckstate = TRUE;
+}
+
+/*
+ * multi_ischanged() is called
+ *
+ * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND
+ * => CONNECT action.
+ *
+ * Set 'clear' to TRUE to have it also clear the state variable.
+ */
+static bool multi_ischanged(struct Curl_multi *multi, bool clear)
+{
+ bool retval = multi->recheckstate;
+ if(clear)
+ multi->recheckstate = FALSE;
+ return retval;
+}
+
static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct timeval now,
struct SessionHandle *data)
@@ -979,6 +1007,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
+ if(multi_ischanged(multi, TRUE)) {
+ DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+ Curl_multi_process_pending_handles(multi);
+ }
+
if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_COMPLETED)
/* Make sure we set the connection's current owner */
@@ -1750,7 +1783,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_MSGSENT);
}
- } while(rc == CURLM_CALL_MULTI_PERFORM);
+ } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
data->result = result;
diff --git a/lib/multihandle.h b/lib/multihandle.h
index 13b32d8fe..cad44d1df 100644
--- a/lib/multihandle.h
+++ b/lib/multihandle.h
@@ -102,6 +102,8 @@ struct Curl_multi {
/* pipelining wanted bits (CURLPIPE*) */
long pipelining;
+ bool recheckstate; /* see Curl_multi_connchanged */
+
/* Shared connection cache (bundles)*/
struct conncache conn_cache;
@@ -144,4 +146,3 @@ struct Curl_multi {
};
#endif /* HEADER_CURL_MULTIHANDLE_H */
-
diff --git a/lib/multiif.h b/lib/multiif.h
index 1a7cf6954..5052f65ae 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -74,6 +74,8 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi);
/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
+void Curl_multi_connchanged(struct Curl_multi *multi);
+
/*
* Curl_multi_closed()
*
diff --git a/lib/url.c b/lib/url.c
index 74f3c9496..483178355 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -3127,7 +3127,9 @@ ConnectionExists(struct SessionHandle *data,
particular host */
bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache);
if(bundle) {
- size_t max_pipe_len = max_pipeline_length(data->multi);
+ /* Max pipe length is zero (unlimited) for multiplexed connections */
+ size_t max_pipe_len = (bundle->multiuse != BUNDLE_MULTIPLEX)?
+ max_pipeline_length(data->multi):0;
size_t best_pipe_len = max_pipe_len;
struct curl_llist_element *curr;
@@ -3352,21 +3354,42 @@ ConnectionExists(struct SessionHandle *data,
}
/* We can't use the connection if the pipe is full */
- if(pipeLen >= max_pipe_len) {
- infof(data, "Pipe is full, skip (%d)\n", pipeLen);
+ if(max_pipe_len && (pipeLen >= max_pipe_len)) {
+ infof(data, "Pipe is full, skip (%zu)\n", pipeLen);
continue;
}
+ /* If multiplexed, make sure we don't go over concurrency limit */
+ if(check->bits.multiplex) {
+ /* Multiplexed connections can only be HTTP/2 for now */
+ struct http_conn *httpc = &check->proto.httpc;
+ if(pipeLen >= httpc->settings.max_concurrent_streams) {
+ infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n",
+ pipeLen);
+ continue;
+ }
+ }
+
/* We can't use the connection if the pipe is penalized */
- if(Curl_pipeline_penalized(data, check))
+ if(Curl_pipeline_penalized(data, check)) {
+ infof(data, "Penalized, skip\n");
continue;
+ }
- if(pipeLen < best_pipe_len) {
- /* This connection has a shorter pipe so far. We'll pick this
- and continue searching */
+ if(max_pipe_len) {
+ if(pipeLen < best_pipe_len) {
+ /* This connection has a shorter pipe so far. We'll pick this
+ and continue searching */
+ chosen = check;
+ best_pipe_len = pipeLen;
+ continue;
+ }
+ }
+ else {
+ /* When not pipelining (== multiplexed), we have a match here! */
chosen = check;
- best_pipe_len = pipeLen;
- continue;
+ infof(data, "Multiplexed connection found!\n");
+ break;
}
}
else {