mirror of https://github.com/openssl/openssl.git
Do batching of stream requests
We have a limited number of streams to use send requests in accordance with the number of streams we have and batch requests according to that limit Reviewed-by: Sasa Nedvedicky <sashan@openssl.org> Reviewed-by: Viktor Dukhovni <viktor@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/25426)
This commit is contained in:
parent
34d6ec804b
commit
1b6638b1d8
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
*
|
*
|
||||||
|
|
@ -41,6 +42,8 @@
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
static int handle_io_failure(SSL *ssl, int res);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A static pointer to a BIO object representing the session's BIO.
|
* @brief A static pointer to a BIO object representing the session's BIO.
|
||||||
*
|
*
|
||||||
|
|
@ -67,6 +70,7 @@ static BIO *session_bio = NULL;
|
||||||
*/
|
*/
|
||||||
static BIO *bio_keylog = NULL;
|
static BIO *bio_keylog = NULL;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a BIO object for a UDP socket connection to a server.
|
* @brief Creates a BIO object for a UDP socket connection to a server.
|
||||||
*
|
*
|
||||||
|
|
@ -176,7 +180,6 @@ static BIO *create_socket_bio(const char *hostname, const char *port,
|
||||||
return bio;
|
return bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Waits for activity on the SSL socket, either for reading or writing.
|
* @brief Waits for activity on the SSL socket, either for reading or writing.
|
||||||
*
|
*
|
||||||
|
|
@ -439,7 +442,6 @@ static int cache_new_session(struct ssl_st *ssl, SSL_SESSION *sess)
|
||||||
if (!PEM_write_bio_SSL_SESSION(session_bio, sess))
|
if (!PEM_write_bio_SSL_SESSION(session_bio, sess))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fprintf(stderr, "Writing a new session to the cache\n");
|
|
||||||
(void)BIO_flush(session_bio);
|
(void)BIO_flush(session_bio);
|
||||||
/* only cache one session */
|
/* only cache one session */
|
||||||
session_cached = 1;
|
session_cached = 1;
|
||||||
|
|
@ -513,7 +515,124 @@ err:
|
||||||
|
|
||||||
static SSL_POLL_ITEM *poll_list = NULL;
|
static SSL_POLL_ITEM *poll_list = NULL;
|
||||||
static BIO **outbiolist = NULL;
|
static BIO **outbiolist = NULL;
|
||||||
|
static char **outnames = NULL;
|
||||||
static size_t poll_count = 0;
|
static size_t poll_count = 0;
|
||||||
|
static char **req_array = NULL;
|
||||||
|
static size_t total_requests = 0;
|
||||||
|
static size_t req_idx = 0;
|
||||||
|
|
||||||
|
static size_t build_request_set(SSL *ssl)
|
||||||
|
{
|
||||||
|
size_t poll_idx;
|
||||||
|
char *req;
|
||||||
|
char outfilename[1024];
|
||||||
|
char req_string[1024];
|
||||||
|
SSL *new_stream;
|
||||||
|
size_t written;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free any previous poll lists
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (poll_idx = 0; poll_idx < poll_count; poll_idx++) {
|
||||||
|
(void)BIO_flush(outbiolist[poll_idx]);
|
||||||
|
BIO_free(outbiolist[poll_idx]);
|
||||||
|
SSL_free(poll_list[poll_idx].desc.value.ssl);
|
||||||
|
}
|
||||||
|
OPENSSL_free(outbiolist);
|
||||||
|
OPENSSL_free(outnames);
|
||||||
|
OPENSSL_free(poll_list);
|
||||||
|
outnames = NULL;
|
||||||
|
poll_list = NULL;
|
||||||
|
outbiolist = NULL;
|
||||||
|
|
||||||
|
poll_count = 0;
|
||||||
|
|
||||||
|
while (req_idx < total_requests) {
|
||||||
|
req = req_array[req_idx];
|
||||||
|
poll_count++;
|
||||||
|
poll_idx = poll_count - 1;
|
||||||
|
|
||||||
|
poll_list = OPENSSL_realloc(poll_list,
|
||||||
|
sizeof(SSL_POLL_ITEM) * poll_count);
|
||||||
|
if (poll_list == NULL) {
|
||||||
|
fprintf(stderr, "Unable to realloc poll_list\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
outbiolist = OPENSSL_realloc(outbiolist,
|
||||||
|
sizeof(BIO *) * poll_count);
|
||||||
|
if (outbiolist == NULL) {
|
||||||
|
fprintf(stderr, "Unable to realloc outbiolist\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
outnames = OPENSSL_realloc(outnames, sizeof(char *) * poll_count);
|
||||||
|
if (outnames == NULL) {
|
||||||
|
fprintf(stderr, "Unable to realloc outnames\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
outnames[poll_idx] = req;
|
||||||
|
|
||||||
|
/* Format the http request */
|
||||||
|
sprintf(req_string, "GET /%s\r\n", req);
|
||||||
|
|
||||||
|
/* build the outfile request path */
|
||||||
|
memset(outfilename, 0, 1024);
|
||||||
|
sprintf(outfilename, "/downloads/%s", req);
|
||||||
|
|
||||||
|
/* open a bio to write the file */
|
||||||
|
outbiolist[poll_idx] = BIO_new_file(outfilename, "w+");
|
||||||
|
if (outbiolist[poll_idx] == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open outfile %s\n", outfilename);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a request stream */
|
||||||
|
new_stream = NULL;
|
||||||
|
if (poll_count <= 99)
|
||||||
|
new_stream = SSL_new_stream(ssl, 0);
|
||||||
|
|
||||||
|
if (new_stream == NULL) {
|
||||||
|
/*
|
||||||
|
* We ran out of new streams to allocate
|
||||||
|
* return and process this batch before getting more
|
||||||
|
*/
|
||||||
|
poll_count--;
|
||||||
|
return poll_count;
|
||||||
|
}
|
||||||
|
poll_list[poll_idx].desc = SSL_as_poll_descriptor(new_stream);
|
||||||
|
poll_list[poll_idx].revents = 0;
|
||||||
|
poll_list[poll_idx].events = SSL_POLL_EVENT_R;
|
||||||
|
|
||||||
|
/* Write an HTTP GET request to the peer */
|
||||||
|
while (!SSL_write_ex2(poll_list[poll_idx].desc.value.ssl,
|
||||||
|
req_string, strlen(req_string),
|
||||||
|
SSL_WRITE_FLAG_CONCLUDE, &written)) {
|
||||||
|
fprintf(stderr, "Write failed\n");
|
||||||
|
if (handle_io_failure(poll_list[poll_idx].desc.value.ssl, 0) == 1)
|
||||||
|
continue; /* Retry */
|
||||||
|
fprintf(stderr, "Failed to write start of HTTP request\n");
|
||||||
|
goto err; /* Cannot retry: error */
|
||||||
|
}
|
||||||
|
|
||||||
|
req_idx++;
|
||||||
|
}
|
||||||
|
return poll_count;
|
||||||
|
|
||||||
|
err:
|
||||||
|
for (poll_idx = 0; poll_idx < poll_count; poll_idx++) {
|
||||||
|
BIO_free(outbiolist[poll_idx]);
|
||||||
|
SSL_free(poll_list[poll_idx].desc.value.ssl);
|
||||||
|
}
|
||||||
|
OPENSSL_free(poll_list);
|
||||||
|
OPENSSL_free(outbiolist);
|
||||||
|
poll_list = NULL;
|
||||||
|
outbiolist = NULL;
|
||||||
|
poll_count = 0;
|
||||||
|
return poll_count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Entry point for the QUIC hq-interop client demo application.
|
* @brief Entry point for the QUIC hq-interop client demo application.
|
||||||
|
|
@ -547,26 +666,26 @@ int main(int argc, char *argv[])
|
||||||
BIO *req_bio = NULL;
|
BIO *req_bio = NULL;
|
||||||
int res = EXIT_FAILURE;
|
int res = EXIT_FAILURE;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned char alpn[] = { 10, 'h','q','-','i','n','t','e','r','o','p'};
|
|
||||||
char req_string[1024];
|
char req_string[1024];
|
||||||
size_t written, readbytes = 0;
|
size_t readbytes = 0;
|
||||||
char buf[160];
|
char buf[160];
|
||||||
BIO_ADDR *peer_addr = NULL;
|
|
||||||
int eof = 0;
|
int eof = 0;
|
||||||
char *hostname, *port;
|
|
||||||
int ipv6 = 0;
|
|
||||||
int argnext = 1;
|
int argnext = 1;
|
||||||
char *reqfile = NULL;
|
char *reqfile = NULL;
|
||||||
char *sslkeylogfile = NULL;
|
char *sslkeylogfile = NULL;
|
||||||
char *reqnames = OPENSSL_zalloc(1025);
|
char *reqnames = OPENSSL_zalloc(1025);
|
||||||
size_t read_offset = 0;
|
size_t read_offset = 0;
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
char *req = NULL, *saveptr = NULL;
|
|
||||||
char outfilename[1024];
|
|
||||||
size_t poll_idx = 0;
|
size_t poll_idx = 0;
|
||||||
size_t poll_done = 0;
|
size_t poll_done = 0;
|
||||||
size_t result_count = 0;
|
size_t result_count = 0;
|
||||||
struct timeval poll_timeout;
|
struct timeval poll_timeout;
|
||||||
|
size_t this_poll_count = 0;
|
||||||
|
char *req, *saveptr = NULL;
|
||||||
|
char *hostname, *port;
|
||||||
|
int ipv6 = 0;
|
||||||
|
unsigned char alpn[] = { 10, 'h','q','-','i','n','t','e','r','o','p'};
|
||||||
|
BIO_ADDR *peer_addr = NULL;
|
||||||
|
|
||||||
if (argc < 4) {
|
if (argc < 4) {
|
||||||
fprintf(stderr, "Usage: quic-hq-interop [-6] hostname port file\n");
|
fprintf(stderr, "Usage: quic-hq-interop [-6] hostname port file\n");
|
||||||
|
|
@ -586,10 +705,6 @@ int main(int argc, char *argv[])
|
||||||
reqfile = argv[argnext];
|
reqfile = argv[argnext];
|
||||||
|
|
||||||
memset(req_string, 0, 1024);
|
memset(req_string, 0, 1024);
|
||||||
#if 0
|
|
||||||
sprintf(req_string, "GET /%s\r\n",
|
|
||||||
reqfile);
|
|
||||||
#endif
|
|
||||||
req_bio = BIO_new_file(reqfile, "r");
|
req_bio = BIO_new_file(reqfile, "r");
|
||||||
if (req_bio == NULL) {
|
if (req_bio == NULL) {
|
||||||
fprintf(stderr, "Failed to open request file %s\n", reqfile);
|
fprintf(stderr, "Failed to open request file %s\n", reqfile);
|
||||||
|
|
@ -704,7 +819,7 @@ int main(int argc, char *argv[])
|
||||||
* The underlying socket is always nonblocking with QUIC, but the default
|
* The underlying socket is always nonblocking with QUIC, but the default
|
||||||
* behaviour of the SSL object is still to block. We set it for nonblocking
|
* behaviour of the SSL object is still to block. We set it for nonblocking
|
||||||
* mode in this demo.
|
* mode in this demo.
|
||||||
{*/
|
*/
|
||||||
if (!SSL_set_blocking_mode(ssl, 0)) {
|
if (!SSL_set_blocking_mode(ssl, 0)) {
|
||||||
fprintf(stderr, "Failed to turn off blocking mode\n");
|
fprintf(stderr, "Failed to turn off blocking mode\n");
|
||||||
goto end;
|
goto end;
|
||||||
|
|
@ -718,78 +833,31 @@ int main(int argc, char *argv[])
|
||||||
goto end; /* Cannot retry: error */
|
goto end; /* Cannot retry: error */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send an http1.0 request for each item in reqnames */
|
|
||||||
req = strtok_r(reqnames, " ", &saveptr);
|
req = strtok_r(reqnames, " ", &saveptr);
|
||||||
|
|
||||||
while (req != NULL) {
|
while (req != NULL) {
|
||||||
|
total_requests++;
|
||||||
poll_count++;
|
req_array = OPENSSL_realloc(req_array, sizeof(char *) * total_requests);
|
||||||
poll_idx = poll_count - 1;
|
req_array[total_requests-1] = req;
|
||||||
poll_list = OPENSSL_realloc(poll_list,
|
req = strtok_r(NULL, " ", &saveptr);
|
||||||
sizeof(SSL_POLL_ITEM) * poll_count);
|
|
||||||
if (poll_list == NULL) {
|
|
||||||
fprintf(stderr, "Unable to realloc poll_list\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
outbiolist = OPENSSL_realloc(outbiolist,
|
|
||||||
sizeof(BIO *) * poll_count);
|
|
||||||
if (outbiolist == NULL) {
|
|
||||||
fprintf(stderr, "Unable to realloc outbiolist\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Format the http request */
|
|
||||||
sprintf(req_string, "GET /%s\r\n", req);
|
|
||||||
|
|
||||||
/* build the outfile request path */
|
|
||||||
memset(outfilename, 0, 1024);
|
|
||||||
sprintf(outfilename, "/downloads/%s", req);
|
|
||||||
|
|
||||||
/* open a bio to write the file */
|
|
||||||
outbiolist[poll_idx] = BIO_new_file(outfilename, "w+");
|
|
||||||
if (outbiolist[poll_idx] == NULL) {
|
|
||||||
fprintf(stderr, "Failed to open outfile %s\n", outfilename);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create a request stream */
|
|
||||||
poll_list[poll_idx].desc = SSL_as_poll_descriptor(SSL_new_stream(ssl, 0));
|
|
||||||
if (poll_list[poll_idx].desc.value.ssl == NULL) {
|
|
||||||
fprintf(stderr, "Failed to create stream request bio\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_list[poll_idx].revents = 0;
|
|
||||||
poll_list[poll_idx].events = SSL_POLL_EVENT_R;
|
|
||||||
|
|
||||||
/* Write an HTTP GET request to the peer */
|
|
||||||
while (!SSL_write_ex2(poll_list[poll_idx].desc.value.ssl,
|
|
||||||
req_string, strlen(req_string),
|
|
||||||
SSL_WRITE_FLAG_CONCLUDE, &written)) {
|
|
||||||
fprintf(stderr, "Write failed\n");
|
|
||||||
if (handle_io_failure(poll_list[poll_idx].desc.value.ssl, 0) == 1)
|
|
||||||
continue; /* Retry */
|
|
||||||
fprintf(stderr, "Failed to write start of HTTP request\n");
|
|
||||||
goto end; /* Cannot retry: error */
|
|
||||||
}
|
|
||||||
req = strtok_r(NULL, " ", &saveptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get a list of requests to poll */
|
||||||
|
this_poll_count = build_request_set(ssl);
|
||||||
/*
|
/*
|
||||||
* Now poll all our descriptors for events
|
* Now poll all our descriptors for events
|
||||||
*/
|
*/
|
||||||
while (poll_done < poll_count) {
|
while (this_poll_count != 0 && poll_done < this_poll_count) {
|
||||||
result_count = 0;
|
result_count = 0;
|
||||||
poll_timeout.tv_sec = 0;
|
poll_timeout.tv_sec = 0;
|
||||||
poll_timeout.tv_usec = 0;
|
poll_timeout.tv_usec = 0;
|
||||||
if (!SSL_poll(poll_list, poll_count, sizeof(SSL_POLL_ITEM),
|
if (!SSL_poll(poll_list, this_poll_count, sizeof(SSL_POLL_ITEM),
|
||||||
&poll_timeout, 0, &result_count)) {
|
&poll_timeout, 0, &result_count)) {
|
||||||
fprintf(stderr, "Failed to poll\n");
|
fprintf(stderr, "Failed to poll\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (poll_idx = 0; poll_idx < poll_count; poll_idx++) {
|
for (poll_idx = 0; poll_idx < this_poll_count; poll_idx++) {
|
||||||
if (result_count == 0)
|
if (result_count == 0)
|
||||||
break;
|
break;
|
||||||
if (poll_list[poll_idx].revents == SSL_POLL_EVENT_R) {
|
if (poll_list[poll_idx].revents == SSL_POLL_EVENT_R) {
|
||||||
|
|
@ -799,6 +867,7 @@ int main(int argc, char *argv[])
|
||||||
* Get up to sizeof(buf) bytes of the response. We keep reading until
|
* Get up to sizeof(buf) bytes of the response. We keep reading until
|
||||||
* the server closes the connection.
|
* the server closes the connection.
|
||||||
*/
|
*/
|
||||||
|
eof = 0;
|
||||||
if (!SSL_read_ex(poll_list[poll_idx].desc.value.ssl, buf,
|
if (!SSL_read_ex(poll_list[poll_idx].desc.value.ssl, buf,
|
||||||
sizeof(buf), &readbytes)) {
|
sizeof(buf), &readbytes)) {
|
||||||
switch (handle_io_failure(poll_list[poll_idx].desc.value.ssl,
|
switch (handle_io_failure(poll_list[poll_idx].desc.value.ssl,
|
||||||
|
|
@ -825,17 +894,28 @@ int main(int argc, char *argv[])
|
||||||
if (!eof) {
|
if (!eof) {
|
||||||
BIO_write(outbiolist[poll_idx], buf, readbytes);
|
BIO_write(outbiolist[poll_idx], buf, readbytes);
|
||||||
} else {
|
} else {
|
||||||
|
fprintf(stderr, "completed %s\n", outnames[poll_idx]);
|
||||||
/* This file is done, take it out of polling contention */
|
/* This file is done, take it out of polling contention */
|
||||||
poll_list[poll_idx].events = 0;
|
poll_list[poll_idx].events = 0;
|
||||||
poll_done++;
|
poll_done++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we've completed this poll set, try get another one
|
||||||
|
*/
|
||||||
|
if (poll_done == this_poll_count) {
|
||||||
|
this_poll_count = build_request_set(ssl);
|
||||||
|
poll_done=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Repeatedly call SSL_shutdown() until the connection is fully
|
* Repeatedly call SSL_shutdown() until the connection is fully
|
||||||
* closed.
|
* closed.
|
||||||
*/
|
*/
|
||||||
|
fprintf(stderr, "Shutting down\n");
|
||||||
while ((ret = SSL_shutdown(ssl)) != 1) {
|
while ((ret = SSL_shutdown(ssl)) != 1) {
|
||||||
if (ret < 0 && handle_io_failure(ssl, ret) == 1)
|
if (ret < 0 && handle_io_failure(ssl, ret) == 1)
|
||||||
continue; /* Retry */
|
continue; /* Retry */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue