apps: support sendfile in s_server when ktls enabled

When the -WWW or -HTTP option is specified, s_server can choose
to use SSL_sendfile to transmit the file requested by client
with KTLS is enabled, taking full advantage of the performance
advantages of Kernel TLS, and adding the '-sendfile' command
line parameter to control this behavior.

Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>

Reviewed-by: Paul Yang <kaishen.yy@antfin.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11318)
This commit is contained in:
Tianjia Zhang 2020-03-13 11:24:05 +08:00 committed by Paul Yang
parent 96ebe52e89
commit cd81ac7be3
2 changed files with 93 additions and 25 deletions

View File

@ -103,6 +103,8 @@ static int keymatexportlen = 20;
static int async = 0;
static int use_sendfile = 0;
static const char *session_id_prefix = NULL;
#ifndef OPENSSL_NO_DTLS
@ -749,7 +751,7 @@ typedef enum OPTION_choice {
OPT_SSL3, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1,
OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, OPT_STATELESS,
OPT_ID_PREFIX, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, OPT_SENDFILE,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA,
OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY, OPT_SCTP_LABEL_BUG,
@ -981,6 +983,9 @@ const OPTIONS s_server_options[] = {
#endif
{"alpn", OPT_ALPN, 's',
"Set the advertised protocols for the ALPN extension (comma-separated list)"},
#ifndef OPENSSL_NO_KTLS
{"sendfile", OPT_SENDFILE, '-', "Use sendfile to response file with -WWW"},
#endif
OPT_R_OPTIONS,
OPT_S_OPTIONS,
@ -1095,6 +1100,7 @@ int s_server_main(int argc, char *argv[])
s_quiet = 0;
s_brief = 0;
async = 0;
use_sendfile = 0;
cctx = SSL_CONF_CTX_new();
vpm = X509_VERIFY_PARAM_new();
@ -1643,6 +1649,11 @@ int s_server_main(int argc, char *argv[])
case OPT_HTTP_SERVER_BINMODE:
http_server_binmode = 1;
break;
case OPT_SENDFILE:
#ifndef OPENSSL_NO_KTLS
use_sendfile = 1;
#endif
break;
}
}
argc = opt_num_rest();
@ -1695,6 +1706,13 @@ int s_server_main(int argc, char *argv[])
}
#endif
#ifndef OPENSSL_NO_KTLS
if (use_sendfile && www <= 1) {
BIO_printf(bio_err, "Can't use -sendfile without -WWW or -HTTP\n");
goto end;
}
#endif
if (!app_passwd(passarg, dpassarg, &pass, &dpass)) {
BIO_printf(bio_err, "Error getting password\n");
goto end;
@ -3336,38 +3354,79 @@ static int www_body(int s, int stype, int prot, unsigned char *context)
"HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n");
}
/* send the file */
for (;;) {
i = BIO_read(file, buf, bufsize);
if (i <= 0)
break;
#ifndef OPENSSL_NO_KTLS
if (use_sendfile) {
FILE *fp = NULL;
int fd;
struct stat st;
off_t offset = 0;
size_t filesize;
#ifdef RENEG
total_bytes += i;
BIO_printf(bio_err, "%d\n", i);
if (total_bytes > 3 * 1024) {
total_bytes = 0;
BIO_printf(bio_err, "RENEGOTIATE\n");
SSL_renegotiate(con);
BIO_get_fp(file, &fp);
fd = fileno(fp);
if (fstat(fd, &st) < 0) {
BIO_printf(io, "Error fstat '%s'\r\n", p);
ERR_print_errors(io);
goto write_error;
}
#endif
for (j = 0; j < i;) {
filesize = st.st_size;
if (((int)BIO_flush(io)) < 0)
goto write_error;
for (;;) {
i = SSL_sendfile(con, fd, offset, filesize, 0);
if (i < 0) {
BIO_printf(io, "Error SSL_sendfile '%s'\r\n", p);
ERR_print_errors(io);
break;
} else {
offset += i;
filesize -= i;
}
if (filesize <= 0) {
if (!s_quiet)
BIO_printf(bio_err, "KTLS SENDFILE '%s' OK\n", p);
break;
}
}
} else
#endif
{
for (;;) {
i = BIO_read(file, buf, bufsize);
if (i <= 0)
break;
#ifdef RENEG
static count = 0;
if (++count == 13) {
total_bytes += i;
BIO_printf(bio_err, "%d\n", i);
if (total_bytes > 3 * 1024) {
total_bytes = 0;
BIO_printf(bio_err, "RENEGOTIATE\n");
SSL_renegotiate(con);
}
#endif
k = BIO_write(io, &(buf[j]), i - j);
if (k <= 0) {
if (!BIO_should_retry(io)
&& !SSL_waiting_for_async(con))
goto write_error;
else {
BIO_printf(bio_s_out, "rwrite W BLOCK\n");
for (j = 0; j < i;) {
#ifdef RENEG
static count = 0;
if (++count == 13)
SSL_renegotiate(con);
#endif
k = BIO_write(io, &(buf[j]), i - j);
if (k <= 0) {
if (!BIO_should_retry(io)
&& !SSL_waiting_for_async(con)) {
goto write_error;
} else {
BIO_printf(bio_s_out, "rwrite W BLOCK\n");
}
} else {
j += k;
}
} else {
j += k;
}
}
}

View File

@ -124,6 +124,7 @@ B<openssl> B<s_server>
[B<-nextprotoneg> I<val>]
[B<-use_srtp> I<val>]
[B<-alpn> I<val>]
[B<-sendfile>]
[B<-keylogfile> I<outfile>]
[B<-recv_max_early_data> I<int>]
[B<-max_early_data> I<int>]
@ -152,6 +153,8 @@ B<openssl> B<s_server>
=for openssl ifdef ssl3 tls1 tls1_1 tls1_2 tls1_3 dtls mtu dtls1 dtls1_2
=for openssl ifdef sendfile
=head1 DESCRIPTION
This command implements a generic SSL/TLS server which
@ -613,6 +616,12 @@ Protocol names are printable ASCII strings, for example "http/1.1" or
"spdy/3".
The flag B<-nextprotoneg> cannot be specified if B<-tls1_3> is used.
=item B<-sendfile>
If this option is set and KTLS is enabled, SSL_sendfile() will be used
instead of BIO_write() to send the HTTP response requested by a client.
This option is only valid if B<-WWW> or B<-HTTP> is specified.
=item B<-keylogfile> I<outfile>
Appends TLS secrets to the specified keylog file such that external programs