diff options
author | Timo Teräs <timo.teras@iki.fi> | 2016-06-02 22:10:06 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2016-11-15 22:25:14 +0200 |
commit | 070a51bf7c00f49bb82d26e889b88906a9b2fd0c (patch) | |
tree | fddd2462220284d9dd7abba8ec2c1c0d68a68159 /main/tcptls.c | |
parent | 0cc14597b29203259b5e6ae4496f9f6d4f4e76f2 (diff) |
Implement internal abstraction for iostreams
fopencookie/funclose is a non-standard API and should not be used
in portable software. Additionally, the way FILE's fd is used in
non-blocking mode is undefined behaviour and cannot be relied on.
This introduces internal abstraction for io streams, that allows
implementing the desired virtualization of read/write operations
with necessary timeout handling.
ASTERISK-24515 #close
ASTERISK-24517 #close
Change-Id: Id916aef418b665ced6a7489aef74908b6e376e85
Diffstat (limited to 'main/tcptls.c')
-rw-r--r-- | main/tcptls.c | 711 |
1 files changed, 91 insertions, 620 deletions
diff --git a/main/tcptls.c b/main/tcptls.c index 262fca074..c8ebab434 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -47,506 +47,13 @@ #include "asterisk/astobj2.h" #include "asterisk/pbx.h" -/*! ao2 object used for the FILE stream fopencookie()/funopen() cookie. */ -struct ast_tcptls_stream { - /*! SSL state if not NULL */ - SSL *ssl; - /*! - * \brief Start time from when an I/O sequence must complete - * by struct ast_tcptls_stream.timeout. - * - * \note If struct ast_tcptls_stream.start.tv_sec is zero then - * start time is the current I/O request. - */ - struct timeval start; - /*! - * \brief The socket returned by accept(). - * - * \note Set to -1 if the stream is closed. - */ - int fd; - /*! - * \brief Timeout in ms relative to struct ast_tcptls_stream.start - * to wait for an event on struct ast_tcptls_stream.fd. - * - * \note Set to -1 to disable timeout. - * \note The socket needs to be set to non-blocking for the timeout - * feature to work correctly. - */ - int timeout; - /*! TRUE if stream can exclusively wait for fd input. */ - int exclusive_input; -}; - -void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream) -{ - ast_assert(stream != NULL); - - stream->timeout = -1; -} - -void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout) -{ - ast_assert(stream != NULL); - - stream->start.tv_sec = 0; - stream->timeout = timeout; -} - -void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout) -{ - ast_assert(stream != NULL); - - stream->start = start; - stream->timeout = timeout; -} - -void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input) -{ - ast_assert(stream != NULL); - - stream->exclusive_input = exclusive_input; -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream read function. - * - * \param cookie Stream control data. - * \param buf Where to put read data. - * \param size Size of the buffer. - * - * \retval number of bytes put into buf. - * \retval 0 on end of file. - * \retval -1 on error. - */ -static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size) -{ - struct ast_tcptls_stream *stream = cookie; - struct timeval start; - int ms; - int res; - - if (!size) { - /* You asked for no data you got no data. */ - return 0; - } - - if (!stream || stream->fd == -1) { - errno = EBADF; - return -1; - } - - if (stream->start.tv_sec) { - start = stream->start; - } else { - start = ast_tvnow(); - } - -#if defined(DO_SSL) - if (stream->ssl) { - for (;;) { - res = SSL_read(stream->ssl, buf, size); - if (0 < res) { - /* We read some payload data. */ - return res; - } - switch (SSL_get_error(stream->ssl, res)) { - case SSL_ERROR_ZERO_RETURN: - /* Report EOF for a shutdown */ - ast_debug(1, "TLS clean shutdown alert reading data\n"); - return 0; - case SSL_ERROR_WANT_READ: - if (!stream->exclusive_input) { - /* We cannot wait for data now. */ - errno = EAGAIN; - return -1; - } - while ((ms = ast_remaining_ms(start, stream->timeout))) { - res = ast_wait_for_input(stream->fd, ms); - if (0 < res) { - /* Socket is ready to be read. */ - break; - } - if (res < 0) { - if (errno == EINTR || errno == EAGAIN) { - /* Try again. */ - continue; - } - ast_debug(1, "TLS socket error waiting for read data: %s\n", - strerror(errno)); - return -1; - } - } - break; - case SSL_ERROR_WANT_WRITE: - while ((ms = ast_remaining_ms(start, stream->timeout))) { - res = ast_wait_for_output(stream->fd, ms); - if (0 < res) { - /* Socket is ready to be written. */ - break; - } - if (res < 0) { - if (errno == EINTR || errno == EAGAIN) { - /* Try again. */ - continue; - } - ast_debug(1, "TLS socket error waiting for write space: %s\n", - strerror(errno)); - return -1; - } - } - break; - default: - /* Report EOF for an undecoded SSL or transport error. */ - ast_debug(1, "TLS transport or SSL error reading data\n"); - return 0; - } - if (!ms) { - /* Report EOF for a timeout */ - ast_debug(1, "TLS timeout reading data\n"); - return 0; - } - } - } -#endif /* defined(DO_SSL) */ - - for (;;) { - res = read(stream->fd, buf, size); - if (0 <= res || !stream->exclusive_input) { - /* Got data or we cannot wait for it. */ - return res; - } - if (errno != EINTR && errno != EAGAIN) { - /* Not a retryable error. */ - ast_debug(1, "TCP socket error reading data: %s\n", - strerror(errno)); - return -1; - } - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report EOF for a timeout */ - ast_debug(1, "TCP timeout reading data\n"); - return 0; - } - ast_wait_for_input(stream->fd, ms); - } -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream write function. - * - * \param cookie Stream control data. - * \param buf Where to get data to write. - * \param size Size of the buffer. - * - * \retval number of bytes written from buf. - * \retval -1 on error. - */ -static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size) -{ - struct ast_tcptls_stream *stream = cookie; - struct timeval start; - int ms; - int res; - int written; - int remaining; - - if (!size) { - /* You asked to write no data you wrote no data. */ - return 0; - } - - if (!stream || stream->fd == -1) { - errno = EBADF; - return -1; - } - - if (stream->start.tv_sec) { - start = stream->start; - } else { - start = ast_tvnow(); - } - -#if defined(DO_SSL) - if (stream->ssl) { - written = 0; - remaining = size; - for (;;) { - res = SSL_write(stream->ssl, buf + written, remaining); - if (res == remaining) { - /* Everything was written. */ - return size; - } - if (0 < res) { - /* Successfully wrote part of the buffer. Try to write the rest. */ - written += res; - remaining -= res; - continue; - } - switch (SSL_get_error(stream->ssl, res)) { - case SSL_ERROR_ZERO_RETURN: - ast_debug(1, "TLS clean shutdown alert writing data\n"); - if (written) { - /* Report partial write. */ - return written; - } - errno = EBADF; - return -1; - case SSL_ERROR_WANT_READ: - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report partial write. */ - ast_debug(1, "TLS timeout writing data (want read)\n"); - return written; - } - ast_wait_for_input(stream->fd, ms); - break; - case SSL_ERROR_WANT_WRITE: - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report partial write. */ - ast_debug(1, "TLS timeout writing data (want write)\n"); - return written; - } - ast_wait_for_output(stream->fd, ms); - break; - default: - /* Undecoded SSL or transport error. */ - ast_debug(1, "TLS transport or SSL error writing data\n"); - if (written) { - /* Report partial write. */ - return written; - } - errno = EBADF; - return -1; - } - } - } -#endif /* defined(DO_SSL) */ - - written = 0; - remaining = size; - for (;;) { - res = write(stream->fd, buf + written, remaining); - if (res == remaining) { - /* Yay everything was written. */ - return size; - } - if (0 < res) { - /* Successfully wrote part of the buffer. Try to write the rest. */ - written += res; - remaining -= res; - continue; - } - if (errno != EINTR && errno != EAGAIN) { - /* Not a retryable error. */ - ast_debug(1, "TCP socket error writing: %s\n", strerror(errno)); - if (written) { - return written; - } - return -1; - } - ms = ast_remaining_ms(start, stream->timeout); - if (!ms) { - /* Report partial write. */ - ast_debug(1, "TCP timeout writing data\n"); - return written; - } - ast_wait_for_output(stream->fd, ms); - } -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream close function. - * - * \param cookie Stream control data. - * - * \retval 0 on success. - * \retval -1 on error. - */ -static int tcptls_stream_close(void *cookie) -{ - struct ast_tcptls_stream *stream = cookie; - - if (!stream) { - errno = EBADF; - return -1; - } - - if (stream->fd != -1) { -#if defined(DO_SSL) - if (stream->ssl) { - int res; - - /* - * According to the TLS standard, it is acceptable for an - * application to only send its shutdown alert and then - * close the underlying connection without waiting for - * the peer's response (this way resources can be saved, - * as the process can already terminate or serve another - * connection). - */ - res = SSL_shutdown(stream->ssl); - if (res < 0) { - ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", - SSL_get_error(stream->ssl, res)); - } - - if (!stream->ssl->server) { - /* For client threads, ensure that the error stack is cleared */ -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - ERR_remove_thread_state(NULL); -#else - ERR_remove_state(0); -#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */ - } - - SSL_free(stream->ssl); - stream->ssl = NULL; - } -#endif /* defined(DO_SSL) */ - - /* - * Issuing shutdown() is necessary here to avoid a race - * condition where the last data written may not appear - * in the TCP stream. See ASTERISK-23548 - */ - shutdown(stream->fd, SHUT_RDWR); - if (close(stream->fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } - stream->fd = -1; - } - ao2_t_ref(stream, -1, "Closed tcptls stream cookie"); - - return 0; -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream destructor function. - * - * \param cookie Stream control data. - * - * \return Nothing - */ -static void tcptls_stream_dtor(void *cookie) -{ -#ifdef AST_DEVMODE - /* Since the ast_assert below is the only one using stream, - * and ast_assert is only available with AST_DEVMODE, we - * put this in a conditional to avoid compiler warnings. */ - struct ast_tcptls_stream *stream = cookie; -#endif - - ast_assert(stream->fd == -1); -} - -/*! - * \internal - * \brief fopencookie()/funopen() stream allocation function. - * - * \retval stream_cookie on success. - * \retval NULL on error. - */ -static struct ast_tcptls_stream *tcptls_stream_alloc(void) -{ - struct ast_tcptls_stream *stream; - - stream = ao2_alloc_options(sizeof(*stream), tcptls_stream_dtor, - AO2_ALLOC_OPT_LOCK_NOLOCK); - if (stream) { - stream->fd = -1; - stream->timeout = -1; - } - return stream; -} - -/*! - * \internal - * \brief Open a custom FILE stream for tcptls. - * - * \param stream Stream cookie control data. - * \param ssl SSL state if not NULL. - * \param fd Socket file descriptor. - * \param timeout ms to wait for an event on fd. -1 if timeout disabled. - * - * \retval fp on success. - * \retval NULL on error. - */ -static FILE *tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout) -{ - FILE *fp; - -#if defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ - static const cookie_io_functions_t cookie_funcs = { - tcptls_stream_read, - tcptls_stream_write, - NULL, - tcptls_stream_close - }; -#endif /* defined(HAVE_FOPENCOOKIE) */ - - if (fd == -1) { - /* Socket not open. */ - return NULL; - } - - stream->ssl = ssl; - stream->fd = fd; - stream->timeout = timeout; - ao2_t_ref(stream, +1, "Opening tcptls stream cookie"); - -#if defined(HAVE_FUNOPEN) /* the BSD interface */ - fp = funopen(stream, tcptls_stream_read, tcptls_stream_write, NULL, - tcptls_stream_close); -#elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ - fp = fopencookie(stream, "w+", cookie_funcs); -#else - /* could add other methods here */ - ast_debug(2, "No stream FILE methods attempted!\n"); - fp = NULL; -#endif - - if (!fp) { - stream->fd = -1; - ao2_t_ref(stream, -1, "Failed to open tcptls stream cookie"); - } - return fp; -} - -HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count) -{ - if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) { - ast_log(LOG_ERROR, "TCP/TLS read called on invalid stream.\n"); - errno = EIO; - return -1; - } - - return tcptls_stream_read(tcptls_session->stream_cookie, buf, count); -} - -HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count) -{ - if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) { - ast_log(LOG_ERROR, "TCP/TLS write called on invalid stream.\n"); - errno = EIO; - return -1; - } - - return tcptls_stream_write(tcptls_session->stream_cookie, buf, count); -} - static void session_instance_destructor(void *obj) { struct ast_tcptls_session_instance *i = obj; - if (i->stream_cookie) { - ao2_t_ref(i->stream_cookie, -1, "Destroying tcptls session instance"); - i->stream_cookie = NULL; + if (i->stream) { + ast_iostream_close(i->stream); + i->stream = NULL; } ast_free(i->overflow_buf); ao2_cleanup(i->private_data); @@ -591,9 +98,7 @@ static void *handle_tcptls_connection(void *data) { struct ast_tcptls_session_instance *tcptls_session = data; #ifdef DO_SSL - int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; - int ret; - char err[256]; + SSL *ssl; #endif /* TCP/TLS connections are associated with external protocols, and @@ -608,123 +113,94 @@ static void *handle_tcptls_connection(void *data) return NULL; } - tcptls_session->stream_cookie = tcptls_stream_alloc(); - if (!tcptls_session->stream_cookie) { - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; - } + if (tcptls_session->parent->tls_cfg) { +#ifdef DO_SSL + if (ast_iostream_start_tls(&tcptls_session->stream, tcptls_session->parent->tls_cfg->ssl_ctx, tcptls_session->client) < 0) { + ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; + } - /* - * open a FILE * as appropriate. - */ - if (!tcptls_session->parent->tls_cfg) { - tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL, - tcptls_session->fd, -1); - if (tcptls_session->f) { - if (setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { + ssl = ast_iostream_get_ssl(tcptls_session->stream); + if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) + || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { + X509 *peer; + long res; + peer = SSL_get_peer_certificate(ssl); + if (!peer) { + ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; } - } - } -#ifdef DO_SSL - else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { - SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); - if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { - ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); - } else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, - tcptls_session->ssl, tcptls_session->fd, -1))) { - if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) - || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { - X509 *peer; - long res; - peer = SSL_get_peer_certificate(tcptls_session->ssl); - if (!peer) { - ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; - } - res = SSL_get_verify_result(tcptls_session->ssl); - if (res != X509_V_OK) { - ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); - X509_free(peer); - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; - } - if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { - ASN1_STRING *str; - X509_NAME *name = X509_get_subject_name(peer); - STACK_OF(GENERAL_NAME) *alt_names; - int pos = -1; - int found = 0; - - for (;;) { - /* Walk the certificate to check all available "Common Name" */ - /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ - pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); - if (pos < 0) { - break; - } - - str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); - if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) { - found = 1; - break; - } + res = SSL_get_verify_result(ssl); + if (res != X509_V_OK) { + ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); + X509_free(peer); + ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; + } + if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { + ASN1_STRING *str; + X509_NAME *name = X509_get_subject_name(peer); + STACK_OF(GENERAL_NAME) *alt_names; + int pos = -1; + int found = 0; + + for (;;) { + /* Walk the certificate to check all available "Common Name" */ + /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ + pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); + if (pos < 0) { + break; } + str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); + if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) { + found = 1; + break; + } + } - if (!found) { - alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL); - if (alt_names != NULL) { - int alt_names_count = sk_GENERAL_NAME_num(alt_names); - - for (pos = 0; pos < alt_names_count; pos++) { - const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos); + if (!found) { + alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL); + if (alt_names != NULL) { + int alt_names_count = sk_GENERAL_NAME_num(alt_names); - if (alt_name->type != GEN_DNS) { - continue; - } + for (pos = 0; pos < alt_names_count; pos++) { + const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos); - if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) { - found = 1; - break; - } + if (alt_name->type != GEN_DNS) { + continue; } - sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); + if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) { + found = 1; + break; + } } - } - if (!found) { - ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); - X509_free(peer); - ast_tcptls_close_session_file(tcptls_session); - ao2_ref(tcptls_session, -1); - return NULL; + sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); } } - X509_free(peer); + + if (!found) { + ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); + X509_free(peer); + ast_tcptls_close_session_file(tcptls_session); + ao2_ref(tcptls_session, -1); + return NULL; + } } + X509_free(peer); } - if (!tcptls_session->f) { /* no success opening descriptor stacking */ - SSL_free(tcptls_session->ssl); - } - } -#endif /* DO_SSL */ - - if (!tcptls_session->f) { +#else + ast_log(LOG_ERROR, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); ast_tcptls_close_session_file(tcptls_session); - ast_log(LOG_WARNING, "FILE * open failed!\n"); -#ifndef DO_SSL - if (tcptls_session->parent->tls_cfg) { - ast_log(LOG_ERROR, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); - } -#endif ao2_ref(tcptls_session, -1); return NULL; +#endif /* DO_SSL */ } if (tcptls_session->parent->worker_fn) { @@ -772,7 +248,13 @@ void *ast_tcptls_server_root(void *data) tcptls_session->overflow_buf = ast_str_create(128); flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - tcptls_session->fd = fd; + + tcptls_session->stream = ast_iostream_from_fd(&fd); + if (!tcptls_session->stream) { + ast_log(LOG_WARNING, "No memory for new session iostream\n"); + continue; + } + tcptls_session->parent = desc; ast_sockaddr_copy(&tcptls_session->remote_address, &addr); @@ -1036,7 +518,7 @@ client_start_error: struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_session_args *desc) { - int x = 1; + int fd, x = 1; struct ast_tcptls_session_instance *tcptls_session = NULL; /* Do nothing if nothing has changed */ @@ -1052,8 +534,8 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s close(desc->accept_fd); } - desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? - AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); + fd = desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? + AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if (desc->accept_fd < 0) { ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); @@ -1079,7 +561,11 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s tcptls_session->overflow_buf = ast_str_create(128); tcptls_session->client = 1; - tcptls_session->fd = desc->accept_fd; + tcptls_session->stream = ast_iostream_from_fd(&fd); + if (!tcptls_session->stream) { + goto error; + } + tcptls_session->parent = desc; tcptls_session->parent->worker_fn = NULL; ast_sockaddr_copy(&tcptls_session->remote_address, @@ -1170,24 +656,9 @@ error: void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session) { - if (tcptls_session->f) { - fflush(tcptls_session->f); - if (fclose(tcptls_session->f)) { - ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); - } - tcptls_session->f = NULL; - tcptls_session->fd = -1; - } else if (tcptls_session->fd != -1) { - /* - * Issuing shutdown() is necessary here to avoid a race - * condition where the last data written may not appear - * in the TCP stream. See ASTERISK-23548 - */ - shutdown(tcptls_session->fd, SHUT_RDWR); - if (close(tcptls_session->fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } - tcptls_session->fd = -1; + if (tcptls_session->stream) { + ast_iostream_close(tcptls_session->stream); + tcptls_session->stream = NULL; } else { ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); } |