Add NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS option

And utilize it in nghttp to limit initial max concurrent streams.
This commit is contained in:
Tatsuhiro Tsujikawa 2013-09-14 19:41:49 +09:00
parent c5d7d570e3
commit 99ba622fed
4 changed files with 76 additions and 2 deletions

View File

@ -1202,7 +1202,21 @@ typedef enum {
* is responsible for sending WINDOW_UPDATE with stream ID 0 using * is responsible for sending WINDOW_UPDATE with stream ID 0 using
* `nghttp2_submit_window_update`. * `nghttp2_submit_window_update`.
*/ */
NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE = 2 NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE = 2,
/**
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
* remote endpoint as if it is received in SETTINGS frame. Without
* specifying this option, before the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
* cause problem if local endpoint submits lots of requests
* initially and sending them at once to the remote peer may lead to
* the rejection of some requests. Specifying this option to the
* sensible value, say 100, may avoid this kind of issue. This value
* will be overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 3
} nghttp2_opt; } nghttp2_opt;
/** /**
@ -1230,6 +1244,10 @@ typedef enum {
* sending WINDOW_UPDATE using * sending WINDOW_UPDATE using
* `nghttp2_submit_window_update`. This option defaults to 0. * `nghttp2_submit_window_update`. This option defaults to 0.
* *
* :enum:`NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS`
* The |optval| must be a pointer to ``ssize_t``. It is an error
* if |*optval| is 0 or negative.
*
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *

View File

@ -3264,6 +3264,19 @@ int nghttp2_session_set_option(nghttp2_session *session,
} }
break; break;
} }
case NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS: {
ssize_t sszval;
if(optlen != sizeof(ssize_t)) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
sszval = *(ssize_t*)optval;
if(sszval <= 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] =
sszval;
break;
}
default: default:
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }

View File

@ -91,6 +91,7 @@ struct Config {
std::map<std::string, std::string> headers; std::map<std::string, std::string> headers;
std::string datafile; std::string datafile;
size_t output_upper_thres; size_t output_upper_thres;
ssize_t peer_max_concurrent_streams;
Config() Config()
: null_out(false), : null_out(false),
remote_name(false), remote_name(false),
@ -103,7 +104,8 @@ struct Config {
multiply(1), multiply(1),
timeout(-1), timeout(-1),
window_bits(-1), window_bits(-1),
output_upper_thres(1024*1024) output_upper_thres(1024*1024),
peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS)
{} {}
}; };
@ -623,6 +625,13 @@ struct HttpClient {
if(rv != 0) { if(rv != 0) {
return -1; return -1;
} }
rv = nghttp2_session_set_option(session,
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS,
&config.peer_max_concurrent_streams,
sizeof(config.peer_max_concurrent_streams));
if(rv != 0) {
return -1;
}
if(need_upgrade()) { if(need_upgrade()) {
// Adjust stream user-data depending on the existence of upload // Adjust stream user-data depending on the existence of upload
// data // data
@ -1471,6 +1480,11 @@ void print_help(std::ostream& out)
<< " -p, --pri=<PRIORITY>\n" << " -p, --pri=<PRIORITY>\n"
<< " Sets stream priority. Default: " << " Sets stream priority. Default: "
<< NGHTTP2_PRI_DEFAULT << "\n" << NGHTTP2_PRI_DEFAULT << "\n"
<< " --peer-max-concurrent-streams=<N>\n"
<< " Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS\n"
<< " value of remote endpoint as if it is\n"
<< " received in SETTINGS frame. The default\n"
<< " is large enough as it is seen as unlimited.\n"
<< std::endl; << std::endl;
} }
@ -1495,6 +1509,7 @@ int main(int argc, char **argv)
{"no-flow-control", no_argument, nullptr, 'f'}, {"no-flow-control", no_argument, nullptr, 'f'},
{"upgrade", no_argument, nullptr, 'u'}, {"upgrade", no_argument, nullptr, 'u'},
{"pri", required_argument, nullptr, 'p'}, {"pri", required_argument, nullptr, 'p'},
{"peer-max-concurrent-streams", required_argument, &flag, 3},
{nullptr, 0, nullptr, 0 } {nullptr, 0, nullptr, 0 }
}; };
int option_index = 0; int option_index = 0;
@ -1602,6 +1617,10 @@ int main(int argc, char **argv)
// key option // key option
config.keyfile = optarg; config.keyfile = optarg;
break; break;
case 3:
// peer-max-concurrent-streams option
config.peer_max_concurrent_streams = strtoul(optarg, nullptr, 10);
break;
} }
break; break;
default: default:

View File

@ -3248,6 +3248,7 @@ void test_nghttp2_session_set_option(void)
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
int intval; int intval;
char charval; char charval;
ssize_t sszval;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
nghttp2_session_client_new(&session, &callbacks, NULL); nghttp2_session_client_new(&session, &callbacks, NULL);
@ -3288,6 +3289,29 @@ void test_nghttp2_session_set_option(void)
CU_ASSERT(session->opt_flags & CU_ASSERT(session->opt_flags &
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE); NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE);
sszval = 100;
CU_ASSERT(0 ==
nghttp2_session_set_option
(session,
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS,
&sszval, sizeof(sszval)));
CU_ASSERT(sszval ==
session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]);
sszval = 0;
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
nghttp2_session_set_option
(session,
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS,
&sszval, sizeof(sszval)));
intval = 100;
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
nghttp2_session_set_option
(session,
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS,
&intval, sizeof(intval)));
nghttp2_session_del(session); nghttp2_session_del(session);
} }