25 #include <openssl/err.h>
26 #include <openssl/opensslv.h>
27 #include <openssl/ssl.h>
29 #include <sys/socket.h>
54 #define ERR2STR_BUFSIZE 128
56 static const char *ssl_error_to_string(
int sslerr,
int ret)
60 return "Internal SSL error";
61 case SSL_ERROR_SYSCALL:
63 return "System call EOF";
64 }
else if (ret == -1) {
72 snprintf(buf, ERR2STR_BUFSIZE,
"Underlying BIO error: %s", strerror(errno));
75 return "System call other";
97 if (stream->ssl && SSL_pending(stream->ssl)) {
101 return ast_wait_for_input(stream->fd, timeout);
116 ast_assert(stream != NULL);
118 stream->timeout = -1;
119 stream->timeout_reset = -1;
124 ast_assert(stream != NULL);
126 stream->start.tv_sec = 0;
127 stream->timeout = timeout;
128 stream->timeout_reset = timeout;
133 ast_assert(stream != NULL);
135 stream->start.tv_sec = 0;
136 stream->timeout = timeout;
137 stream->timeout_reset = timeout_reset;
142 ast_assert(stream != NULL);
144 stream->start = start;
145 stream->timeout = timeout;
146 stream->timeout_reset = timeout;
151 ast_assert(stream != NULL);
153 stream->exclusive_input = exclusive_input;
158 ast_assert(stream != NULL);
160 ast_free(stream->sni_hostname);
161 stream->sni_hostname =
ast_strdup(sni_hostname);
163 return stream->sni_hostname ? 0 : -1;
166 static ssize_t iostream_read(
struct ast_iostream *stream,
void *buf,
size_t size)
168 struct timeval start;
172 if (stream->start.tv_sec) {
173 start = stream->start;
183 res = SSL_read(stream->ssl, buf, size);
186 stream->timeout = stream->timeout_reset;
189 sslerr = SSL_get_error(stream->ssl, res);
191 case SSL_ERROR_ZERO_RETURN:
193 ast_debug(1,
"TLS clean shutdown alert reading data\n");
195 case SSL_ERROR_WANT_READ:
196 if (!stream->exclusive_input) {
202 res = ast_wait_for_input(stream->fd, ms);
208 if (errno == EINTR || errno == EAGAIN) {
212 ast_debug(1,
"TLS socket error waiting for read data: %s\n",
218 case SSL_ERROR_WANT_WRITE:
220 res = ast_wait_for_output(stream->fd, ms);
226 if (errno == EINTR || errno == EAGAIN) {
230 ast_debug(1,
"TLS socket error waiting for write space: %s\n",
236 case SSL_ERROR_SYSCALL:
240 ast_debug(1,
"TLS non-recoverable I/O error occurred: %s, %s\n", ERR_error_string(sslerr, err),
241 ssl_error_to_string(sslerr, res));
245 ast_debug(1,
"TLS transport or SSL error reading data: %s, %s\n", ERR_error_string(sslerr, err),
246 ssl_error_to_string(sslerr, res));
251 ast_debug(1,
"TLS timeout reading data\n");
259 res = read(stream->fd, buf, size);
262 stream->timeout = stream->timeout_reset;
265 if (!stream->exclusive_input) {
268 if (errno != EINTR && errno != EAGAIN) {
270 ast_debug(1,
"TCP socket error reading data: %s\n",
277 ast_debug(1,
"TCP timeout reading data\n");
280 ast_wait_for_input(stream->fd, ms);
291 if (!stream || stream->fd == -1) {
297 if (stream->rbuflen) {
299 if (r > stream->rbuflen) {
302 memcpy(buffer, stream->rbufhead, r);
303 stream->rbuflen -= r;
304 stream->rbufhead += r;
308 return iostream_read(stream, buffer, count);
313 size_t remaining = size;
314 ssize_t accum_size = 0;
320 newline = memchr(stream->rbufhead,
'\n', stream->rbuflen);
322 len = newline - stream->rbufhead + 1;
323 if (len > remaining - 1) {
330 if (stream->rbuflen >= remaining - 1) {
334 if (stream->rbuflen) {
336 memcpy(buffer + accum_size, stream->rbufhead, stream->rbuflen);
337 remaining -= stream->rbuflen;
338 accum_size += stream->rbuflen;
341 stream->rbufhead = stream->rbuf;
343 len = iostream_read(stream, stream->rbuf,
sizeof(stream->rbuf));
356 stream->rbuflen += len;
360 memcpy(buffer + accum_size, stream->rbufhead, len);
361 buffer[accum_size + len] = 0;
362 stream->rbuflen -= len;
363 stream->rbufhead += len;
365 return accum_size + len;
371 size_t remaining = size;
375 ret =
ast_iostream_read(stream, buf, remaining >
sizeof(buf) ?
sizeof(buf) : remaining);
387 struct timeval start;
398 if (!stream || stream->fd == -1) {
403 if (stream->start.tv_sec) {
404 start = stream->start;
416 res = SSL_write(stream->ssl, buffer + written, remaining);
417 if (res == remaining) {
427 sslerr = SSL_get_error(stream->ssl, res);
429 case SSL_ERROR_ZERO_RETURN:
430 ast_debug(1,
"TLS clean shutdown alert writing data\n");
437 case SSL_ERROR_WANT_READ:
441 ast_debug(1,
"TLS timeout writing data (want read)\n");
444 ast_wait_for_input(stream->fd, ms);
446 case SSL_ERROR_WANT_WRITE:
450 ast_debug(1,
"TLS timeout writing data (want write)\n");
453 ast_wait_for_output(stream->fd, ms);
457 ast_debug(1,
"TLS transport or SSL error writing data: %s, %s\n", ERR_error_string(sslerr, err),
458 ssl_error_to_string(sslerr, res));
473 res = write(stream->fd, buffer + written, remaining);
474 if (res == remaining) {
484 if (errno != EINTR && errno != EAGAIN) {
486 ast_debug(1,
"TCP socket error writing: %s\n", strerror(errno));
495 ast_debug(1,
"TCP timeout writing data\n");
498 ast_wait_for_output(stream->fd, ms);
504 char sbuf[512], *buf = sbuf;
505 int len, len2, ret = -1;
508 va_start(va, format);
509 len = vsnprintf(buf,
sizeof(sbuf), format, va);
512 if (len >
sizeof(sbuf) - 1) {
514 size_t buf_len = len + 1;
520 va_start(va, format);
521 len2 = vsnprintf(buf, buf_len, format, va);
546 if (stream->fd != -1) {
559 res = SSL_shutdown(stream->ssl);
561 int sslerr = SSL_get_error(stream->ssl, res);
563 ast_log(LOG_ERROR,
"SSL_shutdown() failed: %s, %s\n",
564 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
567 #if !(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000L)) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
568 if (!SSL_is_server(stream->ssl)) {
570 if (!stream->ssl->server) {
573 #if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
574 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
575 ERR_remove_thread_state(NULL);
582 SSL_free(stream->ssl);
592 shutdown(stream->fd, SHUT_RDWR);
593 if (close(stream->fd)) {
594 ast_log(LOG_ERROR,
"close() failed: %s\n", strerror(errno));
598 ao2_t_ref(stream, -1,
"Closed ast_iostream");
603 static void iostream_dtor(
void *cookie)
607 ast_free(stream->sni_hostname);
608 ast_assert(stream->fd == -1);
615 stream = ao2_alloc_options(
sizeof(*stream), iostream_dtor,
618 stream->timeout = -1;
619 stream->timeout_reset = -1;
631 int (*ssl_setup)(SSL *) = client ? SSL_connect : SSL_accept;
634 stream->ssl = SSL_new(ssl_ctx);
636 ast_log(LOG_ERROR,
"Unable to create new SSL connection\n");
647 SSL_set_fd(stream->ssl, stream->fd);
649 if (client && !ast_strlen_zero(stream->sni_hostname)) {
650 if (!SSL_set_tlsext_host_name(stream->ssl, stream->sni_hostname)) {
651 ast_log(LOG_ERROR,
"Unable to set SNI hostname '%s'\n",
652 stream->sni_hostname);
658 res = ssl_setup(stream->ssl);
660 int sslerr = SSL_get_error(stream->ssl, res);
663 ast_log(LOG_ERROR,
"Problem setting up ssl connection: %s, %s\n",
664 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
671 ast_log(LOG_ERROR,
"SSL not enabled in this build\n");
void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input)
Set the iostream if it can exclusively depend upon the set timeouts.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int ast_iostream_wait_for_input(struct ast_iostream *stream, int timeout)
Wait for input on the iostream's file descriptor.
Asterisk main include file. File version handling, generic pbx functions.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
String manipulation functions.
int ast_iostream_start_tls(struct ast_iostream **stream, SSL_CTX *ctx, int client)
Begin TLS on an iostream.
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t count)
Write data to an iostream.
Time-related functions and macros.
ssize_t ast_iostream_discard(struct ast_iostream *stream, size_t count)
Discard the specified number of bytes from an iostream.
void ast_iostream_set_timeout_inactivity(struct ast_iostream *stream, int timeout)
Set the iostream inactivity timeout timer.
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream's file descriptor.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define ast_strdup(str)
A wrapper for strdup()
Definitions to aid in the use of thread local storage.
void ast_iostream_set_timeout_idle_inactivity(struct ast_iostream *stream, int timeout, int timeout_reset)
Set the iostream inactivity & idle timeout timers.
ssize_t ast_iostream_read(struct ast_iostream *stream, void *buffer, size_t count)
Read data from an iostream.
SSL * ast_iostream_get_ssl(struct ast_iostream *stream)
Get a pointer to an iostream's OpenSSL SSL structure.
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
ssize_t ast_iostream_printf(struct ast_iostream *stream, const char *format,...)
Write a formatted string to an iostream.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
void ast_iostream_set_timeout_disable(struct ast_iostream *stream)
Disable the iostream timeout timer.
void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timeval start, int timeout)
Set the iostream I/O sequence timeout timer.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Generic abstraction for input/output streams.
Support for logging to various files, console and syslog Configuration in file logger.conf.
ssize_t ast_iostream_gets(struct ast_iostream *stream, char *buffer, size_t size)
Read a LF-terminated string from an iostream.
int ast_iostream_set_sni_hostname(struct ast_iostream *stream, const char *sni_hostname)
Set the iostream's SNI hostname for TLS client connections.
void ast_iostream_nonblock(struct ast_iostream *stream)
Make an iostream non-blocking.