diff options
author | Jean Boussier <[email protected]> | 2024-12-21 11:27:09 +0100 |
---|---|---|
committer | git <[email protected]> | 2025-01-14 11:54:47 +0000 |
commit | 2f5d31d38ad6918410da1c41936e043f47725d4f (patch) | |
tree | dd7dbddff68ed5983b00782996cf8aecd4fa8218 /ext/openssl/ossl_ssl.c | |
parent | ccb4ba45ed0439764fc44a40469e396187d83a71 (diff) |
[ruby/openssl] Reduce OpenSSL::Buffering#do_write overhead
[Bug #20972]
The `rb_str_new_freeze` was added in https://github.com/ruby/openssl/issues/452
to better handle concurrent use of a Socket, but SSL sockets can't be used
concurrently AFAIK, so we might as well just error cleanly.
By using `rb_str_locktmp` we can ensure attempts at concurrent write
will raise an error, be we avoid causing a copy of the bytes.
We also use the newer `String#append_as_bytes` method when available
to save on some more copies.
https://github.com/ruby/openssl/commit/0d8c17aa85
Co-Authored-By: [email protected]
Diffstat (limited to 'ext/openssl/ossl_ssl.c')
-rw-r--r-- | ext/openssl/ossl_ssl.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 2525d0c872..fc7bd2deb7 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -2054,28 +2054,32 @@ ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self) } static VALUE -ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) +ossl_ssl_write_internal_safe(VALUE _args) { + VALUE *args = (VALUE*)_args; + VALUE self = args[0]; + VALUE str = args[1]; + VALUE opts = args[2]; + SSL *ssl; rb_io_t *fptr; int num, nonblock = opts != Qfalse; - VALUE tmp, cb_state; + VALUE cb_state; GetSSL(self, ssl); if (!ssl_started(ssl)) rb_raise(eSSLError, "SSL session is not started yet"); - tmp = rb_str_new_frozen(StringValue(str)); VALUE io = rb_attr_get(self, id_i_io); GetOpenFile(io, fptr); /* SSL_write(3ssl) manpage states num == 0 is undefined */ - num = RSTRING_LENINT(tmp); + num = RSTRING_LENINT(str); if (num == 0) return INT2FIX(0); for (;;) { - int nwritten = SSL_write(ssl, RSTRING_PTR(tmp), num); + int nwritten = SSL_write(ssl, RSTRING_PTR(str), num); cb_state = rb_attr_get(self, ID_callback_state); if (!NIL_P(cb_state)) { @@ -2116,6 +2120,29 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) } } + +static VALUE +ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) +{ + VALUE args[3] = {self, str, opts}; + int state; + str = StringValue(str); + + int frozen = RB_OBJ_FROZEN(str); + if (!frozen) { + str = rb_str_locktmp(str); + } + VALUE result = rb_protect(ossl_ssl_write_internal_safe, (VALUE)args, &state); + if (!frozen) { + rb_str_unlocktmp(str); + } + + if (state) { + rb_jump_tag(state); + } + return result; +} + /* * call-seq: * ssl.syswrite(string) => Integer |