Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 31 additions & 20 deletions vlib/net/openssl/ssl_connection.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -98,37 +98,48 @@ pub fn (mut s SSLConn) shutdown() ! {
eprintln(@METHOD)
}

if s.ssl != 0 {
if s.ssl != unsafe { nil } {
deadline := ssl_timeout_deadline(s.duration)
for {
mut res := C.SSL_shutdown(voidptr(s.ssl))
mut shutdown_done := false

for !shutdown_done {
res := C.SSL_shutdown(voidptr(s.ssl))
if res == 1 {
shutdown_done = true
break
}

err_res := ssl_error(res, s.ssl) or {
break // We break to free rest of resources
}
if err_res == .ssl_error_want_read {
s.wait_for_read(ssl_remaining_timeout(deadline))!
continue
} else if err_res == .ssl_error_want_write {
s.wait_for_write(ssl_remaining_timeout(deadline))!
if res == 0 {
// Second SSL_shutdown() needed for full bidirectional shutdown.
continue
Comment on lines +111 to 113

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait on retryable SSL_shutdown(0) results

When the underlying socket is non-blocking, such as builds using -d net_nonblocking_sockets or callers that set the TCP fd non-blocking, OpenSSL can return 0 from SSL_shutdown() because the shutdown is still in progress and SSL_get_error() would report SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE. This unconditional continue skips the existing wait logic below, so shutdown can busy-spin until the fd happens to become ready or forever if it never does; handle res == 0 through ssl_error() and wait/retry instead of immediately looping.

Useful? React with 👍 / 👎.

}
if s.ssl != 0 {
unsafe { C.SSL_free(voidptr(s.ssl)) }
}
if s.sslctx != 0 {
C.SSL_CTX_free(s.sslctx)

err_res := ssl_error(res, s.ssl) or { break }

match err_res {
.ssl_error_want_read {
s.wait_for_read(ssl_remaining_timeout(deadline)) or { break }
}
.ssl_error_want_write {
s.wait_for_write(ssl_remaining_timeout(deadline)) or { break }
}
else {
break
}
}
return error('net.openssl Could not connect using SSL. (${err_res}),err')
}
C.SSL_free(voidptr(s.ssl))

// Always free SSL object first.
if s.ssl != unsafe { nil } {
unsafe { C.SSL_free(voidptr(s.ssl)) }
s.ssl = unsafe { nil }
}
}
if s.sslctx != 0 {

if s.sslctx != unsafe { nil } {
C.SSL_CTX_free(s.sslctx)
s.sslctx = unsafe { nil }
}

if s.owns_socket {
net.shutdown(s.handle)
net.close(s.handle)!
Expand Down
Loading