Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
Typedefs | Functions
iostream.h File Reference

Generic abstraction for input/output streams. More...

#include "asterisk.h"
Include dependency graph for iostream.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef struct ssl_st SSL
 
typedef struct ssl_ctx_st SSL_CTX
 

Functions

void ast_iostream_blocking (struct ast_iostream *stream)
 Make an iostream blocking.
 
int ast_iostream_close (struct ast_iostream *stream)
 Close an iostream.
 
ssize_t ast_iostream_discard (struct ast_iostream *stream, size_t count)
 Discard the specified number of bytes from an iostream.
 
struct ast_iostreamast_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.
 
SSLast_iostream_get_ssl (struct ast_iostream *stream)
 Get a pointer to an iostream's OpenSSL SSL structure.
 
ssize_t ast_iostream_gets (struct ast_iostream *stream, char *buffer, size_t size)
 Read a LF-terminated string from an iostream.
 
void ast_iostream_nonblock (struct ast_iostream *stream)
 Make an iostream non-blocking.
 
ssize_t ast_iostream_printf (struct ast_iostream *stream, const char *format,...)
 Write a formatted string to an iostream.
 
ssize_t ast_iostream_read (struct ast_iostream *stream, void *buffer, size_t count)
 Read data from an iostream.
 
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.
 
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_set_timeout_disable (struct ast_iostream *stream)
 Disable the iostream timeout timer.
 
void ast_iostream_set_timeout_idle_inactivity (struct ast_iostream *stream, int timeout, int timeout_reset)
 Set the iostream inactivity & idle timeout timers.
 
void ast_iostream_set_timeout_inactivity (struct ast_iostream *stream, int timeout)
 Set the iostream inactivity 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_iostream_start_tls (struct ast_iostream **stream, SSL_CTX *ctx, int client)
 Begin TLS on an iostream.
 
int ast_iostream_wait_for_input (struct ast_iostream *stream, int timeout)
 Wait for input on the iostream's file descriptor.
 
ssize_t ast_iostream_write (struct ast_iostream *stream, const void *buffer, size_t count)
 Write data to an iostream.
 

Detailed Description

Generic abstraction for input/output streams.

Definition in file iostream.h.

Typedef Documentation

◆ SSL

typedef struct ssl_st SSL

Definition at line 37 of file iostream.h.

◆ SSL_CTX

typedef struct ssl_ctx_st SSL_CTX

Definition at line 38 of file iostream.h.

Function Documentation

◆ ast_iostream_blocking()

void ast_iostream_blocking ( struct ast_iostream stream)

Make an iostream blocking.

Since
20.21.0
22.11.0
23.5.0
Parameters
streamA pointer to an iostream

Definition at line 109 of file iostream.c.

110{
111 ast_fd_clear_flags(stream->fd, O_NONBLOCK);
112}
#define ast_fd_clear_flags(fd, flags)
Clear flags on the given file descriptor.
Definition utils.h:1095

References ast_fd_clear_flags, and ast_iostream::fd.

Referenced by websocket_client_stop_handshake_timer().

◆ ast_iostream_close()

int ast_iostream_close ( struct ast_iostream stream)

Close an iostream.

Parameters
streamA pointer to an iostream
Return values
0success
-1failure
Note
On failure, errno may be set providing additional information on why the failure occurred.

Definition at line 544 of file iostream.c.

545{
546 if (!stream) {
547 errno = EBADF;
548 return -1;
549 }
550
551 if (stream->fd != -1) {
552#if defined(DO_SSL)
553 if (stream->ssl) {
554 int res;
555
556 /*
557 * According to the TLS standard, it is acceptable for an
558 * application to only send its shutdown alert and then
559 * close the underlying connection without waiting for
560 * the peer's response (this way resources can be saved,
561 * as the process can already terminate or serve another
562 * connection).
563 */
564 res = SSL_shutdown(stream->ssl);
565 if (res < 0) {
566 int sslerr = SSL_get_error(stream->ssl, res);
567 char err[256];
568 ast_log(LOG_ERROR, "SSL_shutdown() failed: %s, %s\n",
569 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
570 }
571
572#if !(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000L)) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
573 if (!SSL_is_server(stream->ssl)) {
574#else
575 if (!stream->ssl->server) {
576#endif
577 /* For client threads, ensure that the error stack is cleared */
578#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
579#if OPENSSL_VERSION_NUMBER >= 0x10000000L
580 ERR_remove_thread_state(NULL);
581#else
582 ERR_remove_state(0);
583#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */
584#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
585 }
586
587 SSL_free(stream->ssl);
588 stream->ssl = NULL;
589 }
590#endif /* defined(DO_SSL) */
591
592 /*
593 * Issuing shutdown() is necessary here to avoid a race
594 * condition where the last data written may not appear
595 * in the TCP stream. See ASTERISK-23548
596 */
597 shutdown(stream->fd, SHUT_RDWR);
598 if (close(stream->fd)) {
599 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
600 }
601 stream->fd = -1;
602 }
603 ao2_t_ref(stream, -1, "Closed ast_iostream");
604
605 return 0;
606}
#define ast_log
Definition astobj2.c:42
#define ao2_t_ref(o, delta, tag)
Definition astobj2.h:460
#define LOG_ERROR
int errno
#define NULL
Definition resample.c:96
SSL * ssl
Definition iostream.c:40

References ao2_t_ref, ast_log, errno, ast_iostream::fd, LOG_ERROR, NULL, and ast_iostream::ssl.

Referenced by app_exec(), ast_tcptls_close_session_file(), auth_http_callback(), close_mansession_file(), generic_http_callback(), session_destroy_fn(), session_instance_destructor(), and websocket_close().

◆ ast_iostream_discard()

ssize_t ast_iostream_discard ( struct ast_iostream stream,
size_t  count 
)

Discard the specified number of bytes from an iostream.

Parameters
streamA pointer to an iostream
countThe number of bytes to discard.
Returns
Upon successful completion, returns the number of bytes discarded. Otherwise, -1 is returned and errno may be set indicating the error.

Definition at line 373 of file iostream.c.

374{
375 char buf[1024];
376 size_t remaining = size;
377 ssize_t ret;
378
379 while (remaining) {
380 ret = ast_iostream_read(stream, buf, remaining > sizeof(buf) ? sizeof(buf) : remaining);
381 if (ret <= 0) {
382 return ret;
383 }
384 remaining -= ret;
385 }
386
387 return size;
388}
char buf[BUFSIZE]
Definition eagi_proxy.c:66
ssize_t ast_iostream_read(struct ast_iostream *stream, void *buffer, size_t count)
Read data from an iostream.
Definition iostream.c:289

References ast_iostream_read(), and buf.

Referenced by http_body_discard_contents().

◆ ast_iostream_from_fd()

struct ast_iostream * ast_iostream_from_fd ( int *  fd)

Create an iostream from a file descriptor.

Parameters
fdA pointer to an open file descriptor
Returns
A newly allocated iostream or NULL if allocation fails.

Definition at line 616 of file iostream.c.

617{
618 struct ast_iostream *stream;
619
620 stream = ao2_alloc_options(sizeof(*stream), iostream_dtor,
622 if (stream) {
623 stream->timeout = -1;
624 stream->timeout_reset = -1;
625 stream->fd = *fd;
626 *fd = -1;
627 }
628
629 return stream;
630}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
static void iostream_dtor(void *cookie)
Definition iostream.c:608
int timeout_reset
Definition iostream.c:44

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ast_iostream::fd, iostream_dtor(), ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by app_exec(), ast_tcptls_client_create(), ast_tcptls_server_root(), auth_http_callback(), and generic_http_callback().

◆ ast_iostream_get_fd()

int ast_iostream_get_fd ( struct ast_iostream stream)

Get an iostream's file descriptor.

Parameters
streamA pointer to an iostream
Returns
The file descriptor for the given iostream
Return values
-1if the iostream has no open file descriptor.

Definition at line 85 of file iostream.c.

86{
87 return stream->fd;
88}

References ast_iostream::fd.

Referenced by action_waitevent(), ast_websocket_client_create_with_options(), ast_websocket_fd(), ast_websocket_uri_cb(), auth_http_callback(), eivr_comm(), get_input(), handle_kickmanconn(), handle_showmanconn(), httpd_helper_thread(), phoneprov_callback(), process_output(), session_do(), and websocket_close().

◆ ast_iostream_get_ssl()

SSL * ast_iostream_get_ssl ( struct ast_iostream stream)

Get a pointer to an iostream's OpenSSL SSL structure.

Parameters
streamA pointer to an iostream
Returns
A pointer to the OpenSSL SSL structure for the given iostream
Return values
NULLif TLS has not been initiated.
Note
If OpenSSL support is not included in the build, this will always return NULL.

Definition at line 114 of file iostream.c.

115{
116 return stream->ssl;
117}

References ast_iostream::ssl.

Referenced by ast_tcptls_start_tls(), ast_websocket_uri_cb(), and websocket_client_connect().

◆ ast_iostream_gets()

ssize_t ast_iostream_gets ( struct ast_iostream stream,
char *  buffer,
size_t  size 
)

Read a LF-terminated string from an iostream.

Parameters
streamA pointer to an iostream
bufferPointer to a buffer to store the read bytes.
sizeThe total size of buffer in bytes.
Returns
The number of bytes stored in buffer, excluding the null byte used to terminate the string. If the size of buffer (indicated by the caller with the size argument) is not sufficient to store the entire line it will be truncated to fit the available space. The contents of buffer will always be terminated with a null byte. In the case of an error, -1 will be returned and errno may be set indicating the error.

Definition at line 316 of file iostream.c.

317{
318 size_t remaining = size;
319 ssize_t accum_size = 0;
320 ssize_t len;
321 char *newline;
322
323 for (;;) {
324 /* Search for newline */
325 newline = memchr(stream->rbufhead, '\n', stream->rbuflen);
326 if (newline) {
327 len = newline - stream->rbufhead + 1;
328 if (len > remaining - 1) {
329 len = remaining - 1;
330 }
331 break;
332 }
333
334 /* Enough buffered line data to fill request buffer? */
335 if (stream->rbuflen >= remaining - 1) {
336 len = remaining - 1;
337 break;
338 }
339 if (stream->rbuflen) {
340 /* Put leftover buffered line data into request buffer */
341 memcpy(buffer + accum_size, stream->rbufhead, stream->rbuflen);
342 remaining -= stream->rbuflen;
343 accum_size += stream->rbuflen;
344 stream->rbuflen = 0;
345 }
346 stream->rbufhead = stream->rbuf;
347
348 len = iostream_read(stream, stream->rbuf, sizeof(stream->rbuf));
349 if (len == 0) {
350 /* Nothing new was read. Return whatever we have accumulated. */
351 break;
352 }
353 if (len < 0) {
354 if (accum_size) {
355 /* We have an accumulated buffer so return that instead. */
356 len = 0;
357 break;
358 }
359 return len;
360 }
361 stream->rbuflen += len;
362 }
363
364 /* Return read buffer string length */
365 memcpy(buffer + accum_size, stream->rbufhead, len);
366 buffer[accum_size + len] = 0;
367 stream->rbuflen -= len;
368 stream->rbufhead += len;
369
370 return accum_size + len;
371}
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size)
Definition iostream.c:171
char * rbufhead
Definition iostream.c:47
char rbuf[2048]
Definition iostream.c:48

References iostream_read(), len(), ast_iostream::rbuf, ast_iostream::rbufhead, and ast_iostream::rbuflen.

Referenced by eivr_comm(), http_body_discard_chunk_trailer_headers(), http_body_get_chunk_length(), http_request_headers_get(), httpd_process_request(), and websocket_client_handshake_get_response().

◆ ast_iostream_nonblock()

void ast_iostream_nonblock ( struct ast_iostream stream)

Make an iostream non-blocking.

Parameters
streamA pointer to an iostream

Definition at line 104 of file iostream.c.

105{
106 ast_fd_set_flags(stream->fd, O_NONBLOCK);
107}
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition utils.h:1079

References ast_fd_set_flags, and ast_iostream::fd.

Referenced by ast_websocket_set_nonblock(), httpd_helper_thread(), session_do(), and websocket_client_start_handshake_timer().

◆ ast_iostream_printf()

ssize_t ast_iostream_printf ( struct ast_iostream stream,
const char *  format,
  ... 
)

Write a formatted string to an iostream.

Parameters
streamA pointer to an iostream
formatA format string, as documented by printf(3)
...Arguments for the provided format string
Returns
The number of bytes written, or -1 if an error occurs. Note that if -1 is returned, the number of bytes written to the iostream is unspecified.

Definition at line 507 of file iostream.c.

508{
509 char sbuf[512], *buf = sbuf;
510 int len, len2, ret = -1;
511 va_list va;
512
513 va_start(va, format);
514 len = vsnprintf(buf, sizeof(sbuf), format, va);
515 va_end(va);
516
517 if (len > sizeof(sbuf) - 1) {
518 /* Add one to the string length to accommodate the NULL byte */
519 size_t buf_len = len + 1;
520
521 buf = ast_malloc(buf_len);
522 if (!buf) {
523 return -1;
524 }
525 va_start(va, format);
526 len2 = vsnprintf(buf, buf_len, format, va);
527 va_end(va);
528 if (len2 != len) {
529 goto error;
530 }
531 }
532
533 if (ast_iostream_write(stream, buf, len) == len)
534 ret = len;
535
536error:
537 if (buf != sbuf) {
538 ast_free(buf);
539 }
540
541 return ret;
542}
#define ast_free(a)
Definition astmm.h:180
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t size)
Write data to an iostream.
Definition iostream.c:390
int error(const char *format,...)

References ast_free, ast_iostream_write(), ast_malloc, buf, error(), and len().

Referenced by ast_http_send(), ast_websocket_uri_cb(), websocket_client_handshake(), and websocket_proxy_handshake().

◆ ast_iostream_read()

ssize_t ast_iostream_read ( struct ast_iostream stream,
void *  buffer,
size_t  count 
)

Read data from an iostream.

Parameters
streamA pointer to an iostream
bufferPointer to a buffer to store the read bytes.
countThe number of bytes to read.
Returns
Upon successful completion, returns a non-negative integer indicating the number of bytes actually read. Otherwise, returns -1 and may set errno to indicate the error.

Definition at line 289 of file iostream.c.

290{
291 if (!count) {
292 /* You asked for no data you got no data. */
293 return 0;
294 }
295
296 if (!stream || stream->fd == -1) {
297 errno = EBADF;
298 return -1;
299 }
300
301 /* Get any remains from the read buffer */
302 if (stream->rbuflen) {
303 size_t r = count;
304 if (r > stream->rbuflen) {
305 r = stream->rbuflen;
306 }
307 memcpy(buffer, stream->rbufhead, r);
308 stream->rbuflen -= r;
309 stream->rbufhead += r;
310 return r;
311 }
312
313 return iostream_read(stream, buffer, count);
314}

References errno, ast_iostream::fd, iostream_read(), ast_iostream::rbufhead, and ast_iostream::rbuflen.

Referenced by ast_iostream_discard(), get_input(), http_body_check_chunk_sync(), http_body_read_contents(), readmimefile(), and ws_safe_read().

◆ ast_iostream_set_exclusive_input()

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.

Parameters
streamA pointer to an iostream
exclusive_inputTRUE if stream can exclusively wait for fd input. Otherwise, the stream will not wait for fd input. It will wait while trying to send data.
Note
The stream timeouts still need to be set.

Definition at line 154 of file iostream.c.

155{
156 ast_assert(stream != NULL);
157
158 stream->exclusive_input = exclusive_input;
159}
int exclusive_input
Definition iostream.c:45
#define ast_assert(a)
Definition utils.h:779

References ast_assert, ast_iostream::exclusive_input, and NULL.

Referenced by ast_websocket_set_nonblock(), ast_websocket_uri_cb(), httpd_helper_thread(), session_do(), websocket_client_start_handshake_timer(), and websocket_client_stop_handshake_timer().

◆ ast_iostream_set_sni_hostname()

int ast_iostream_set_sni_hostname ( struct ast_iostream stream,
const char *  sni_hostname 
)

Set the iostream's SNI hostname for TLS client connections.

Parameters
streamA pointer to an iostream
sni_hostnameThe hostname to use for SNI when in client mode
Return values
0if the hostname was set successfully.
-1if memory could not be allocated for the hostname.

Definition at line 161 of file iostream.c.

162{
163 ast_assert(stream != NULL);
164
165 ast_free(stream->sni_hostname);
166 stream->sni_hostname = ast_strdup(sni_hostname);
167
168 return stream->sni_hostname ? 0 : -1;
169}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
char * sni_hostname
Definition iostream.c:49

References ast_assert, ast_free, ast_strdup, NULL, and ast_iostream::sni_hostname.

Referenced by ast_tcptls_client_create().

◆ ast_iostream_set_timeout_disable()

void ast_iostream_set_timeout_disable ( struct ast_iostream stream)

Disable the iostream timeout timer.

Parameters
streamA pointer to an iostream

Definition at line 119 of file iostream.c.

120{
121 ast_assert(stream != NULL);
122
123 stream->timeout = -1;
124 stream->timeout_reset = -1;
125}

References ast_assert, NULL, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by ast_websocket_write(), send_string(), session_do(), websocket_client_stop_handshake_timer(), and websocket_close().

◆ ast_iostream_set_timeout_idle_inactivity()

void ast_iostream_set_timeout_idle_inactivity ( struct ast_iostream stream,
int  timeout,
int  timeout_reset 
)

Set the iostream inactivity & idle timeout timers.

Parameters
streamA pointer to an iostream
timeoutNumber of milliseconds to wait for initial data transfer with the peer.
timeout_resetNumber of milliseconds to wait for subsequent data transfer with the peer.

As an example, if you want to timeout a peer if they do not send an initial message within 5 seconds or if they do not send a message at least every 30 seconds, you would set timeout to 5000 and timeout_reset to 30000.

Note
Setting either of these timeouts to -1 will disable them.

Definition at line 136 of file iostream.c.

137{
138 ast_assert(stream != NULL);
139
140 stream->start.tv_sec = 0;
141 stream->timeout = timeout;
142 stream->timeout_reset = timeout_reset;
143}
struct timeval start
Definition iostream.c:41

References ast_assert, NULL, ast_iostream::start, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by httpd_helper_thread().

◆ ast_iostream_set_timeout_inactivity()

void ast_iostream_set_timeout_inactivity ( struct ast_iostream stream,
int  timeout 
)

Set the iostream inactivity timeout timer.

Parameters
streamA pointer to an iostream
timeoutNumber of milliseconds to wait for data transfer with the peer.

This is basically how much time we are willing to spend in an I/O call before we declare the peer unresponsive.

Note
Setting timeout to -1 disables the timeout.
Setting this timeout replaces the I/O sequence timeout timer.

Definition at line 127 of file iostream.c.

128{
129 ast_assert(stream != NULL);
130
131 stream->start.tv_sec = 0;
132 stream->timeout = timeout;
133 stream->timeout_reset = timeout;
134}

References ast_assert, NULL, ast_iostream::start, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by send_string(), and websocket_close().

◆ ast_iostream_set_timeout_sequence()

void ast_iostream_set_timeout_sequence ( struct ast_iostream stream,
struct timeval  start,
int  timeout 
)

Set the iostream I/O sequence timeout timer.

Parameters
streamA pointer to an iostream
startTime the I/O sequence timer starts.
timeoutNumber of milliseconds from the start time before timeout.

This is how much time are we willing to allow the peer to complete an operation that can take several I/O calls. The main use is as an authentication timer with us.

Note
Setting timeout to -1 disables the timeout.
Setting this timeout replaces the inactivity timeout timer.

Definition at line 145 of file iostream.c.

146{
147 ast_assert(stream != NULL);
148
149 stream->start = start;
150 stream->timeout = timeout;
151 stream->timeout_reset = timeout;
152}

References ast_assert, NULL, ast_iostream::start, ast_iostream::timeout, and ast_iostream::timeout_reset.

Referenced by ast_websocket_write(), session_do(), and websocket_client_start_handshake_timer().

◆ ast_iostream_start_tls()

int ast_iostream_start_tls ( struct ast_iostream **  stream,
SSL_CTX ctx,
int  client 
)

Begin TLS on an iostream.

Parameters
streamA pointer to an iostream pointer
ctxA pointer to an SSL_CTX which will be passed to SSL_new()
clientNon-zero to indicate that we are the client, zero to indicate that we are the server.
Return values
0success
-1failure
Note
The iostream that is passed in stream may be replaced with a different one before this function returns.
On failure, errno may be set providing additional information on why the failure occurred.

Definition at line 632 of file iostream.c.

633{
634#ifdef DO_SSL
635 struct ast_iostream *stream = *pstream;
636 int (*ssl_setup)(SSL *) = client ? SSL_connect : SSL_accept;
637 int res;
638 struct timeval rcv_timeout, snd_timeout;
639 struct timeval timeout;
640 socklen_t len;
641
642 stream->ssl = SSL_new(ssl_ctx);
643 if (!stream->ssl) {
644 ast_log(LOG_ERROR, "Unable to create new SSL connection\n");
645 errno = ENOMEM;
646 return -1;
647 }
648
649 /*
650 * This function takes struct ast_iostream **, so it can chain
651 * SSL over any ast_iostream. For now we assume it's a file descriptor.
652 * But later this should instead use BIO wrapper to tie SSL to another
653 * ast_iostream.
654 */
655 SSL_set_fd(stream->ssl, stream->fd);
656
657 if (client && !ast_strlen_zero(stream->sni_hostname)) {
658 if (!SSL_set_tlsext_host_name(stream->ssl, stream->sni_hostname)) {
659 ast_log(LOG_ERROR, "Unable to set SNI hostname '%s'\n",
660 stream->sni_hostname);
661 errno = EIO;
662 return -1;
663 }
664 }
665
666 /* Get current socket timeout values */
667 len = sizeof(rcv_timeout);
668 getsockopt(stream->fd, SOL_SOCKET, SO_RCVTIMEO, &rcv_timeout, &len);
669 len = sizeof(snd_timeout);
670 getsockopt(stream->fd, SOL_SOCKET, SO_SNDTIMEO, &snd_timeout, &len);
671
672 /* Set socket timeout for SSL handshake to prevent hanging connections and allow SSL handshake to timeout */
673 timeout.tv_sec = 30; /* 30 second timeout for SSL handshake */
674 timeout.tv_usec = 0;
675 setsockopt(stream->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
676 setsockopt(stream->fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
677
678 res = ssl_setup(stream->ssl);
679 if (res <= 0) {
680 int sslerr = SSL_get_error(stream->ssl, res);
681 char err[256];
682
683 ast_log(LOG_ERROR, "Problem setting up ssl connection: %s, %s\n",
684 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
685 errno = EIO;
686 return -1;
687 }
688
689 /* Restore socket timeouts from SSL handshake */
690 setsockopt(stream->fd, SOL_SOCKET, SO_RCVTIMEO, &rcv_timeout, sizeof(rcv_timeout));
691 setsockopt(stream->fd, SOL_SOCKET, SO_SNDTIMEO, &snd_timeout, sizeof(snd_timeout));
692
693 return 0;
694#else
695 ast_log(LOG_ERROR, "SSL not enabled in this build\n");
696 errno = ENOTSUP;
697 return -1;
698#endif
699}
struct ssl_st SSL
Definition iostream.h:37
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65

References ast_log, ast_strlen_zero(), errno, ast_iostream::fd, len(), LOG_ERROR, ast_iostream::sni_hostname, ast_iostream::ssl, and ast_iostream::start.

Referenced by ast_tcptls_start_tls().

◆ ast_iostream_wait_for_input()

int ast_iostream_wait_for_input ( struct ast_iostream stream,
int  timeout 
)

Wait for input on the iostream's file descriptor.

Since
16.8.0
17.2.0
Parameters
streamA pointer to an iostream
timeoutthe number of milliseconds to wait
Return values
-1if error occurred
0if the timeout expired
1if the stream is ready for reading

Definition at line 90 of file iostream.c.

91{
92#if defined(DO_SSL)
93 /* Because SSL is read in blocks, it's possible that the last time we read we
94 got more than we asked for and it is now buffered inside OpenSSL. If that
95 is the case, calling ast_wait_for_input() will block until the fd is ready
96 for reading again, which might never happen. */
97 if (stream->ssl && SSL_pending(stream->ssl)) {
98 return 1;
99 }
100#endif
101 return ast_wait_for_input(stream->fd, timeout);
102}
int ast_wait_for_input(int fd, int ms)
Definition utils.c:1732

References ast_wait_for_input(), ast_iostream::fd, and ast_iostream::ssl.

Referenced by ast_websocket_wait_for_input(), and ws_safe_read().

◆ ast_iostream_write()

ssize_t ast_iostream_write ( struct ast_iostream stream,
const void *  buffer,
size_t  count 
)

Write data to an iostream.

Parameters
streamA pointer to an iostream
bufferPointer to a buffer from which to read bytes.
countThe number of bytes from buffer to write.
Returns
Upon successful completion, returns the number of bytes actually written to the iostream. This number shall never be greater than count. Otherwise, returns -1 and may set errno to indicate the error.

Definition at line 390 of file iostream.c.

391{
392 struct timeval start;
393 int ms;
394 int res;
395 int written;
396 int remaining;
397
398 if (!size) {
399 /* You asked to write no data you wrote no data. */
400 return 0;
401 }
402
403 if (!stream || stream->fd == -1) {
404 errno = EBADF;
405 return -1;
406 }
407
408 if (stream->start.tv_sec) {
409 start = stream->start;
410 } else {
411 start = ast_tvnow();
412 }
413
414#if defined(DO_SSL)
415 if (stream->ssl) {
416 written = 0;
417 remaining = size;
418 for (;;) {
419 int sslerr;
420 char err[256];
421 res = SSL_write(stream->ssl, buffer + written, remaining);
422 if (res == remaining) {
423 /* Everything was written. */
424 return size;
425 }
426 if (0 < res) {
427 /* Successfully wrote part of the buffer. Try to write the rest. */
428 written += res;
429 remaining -= res;
430 continue;
431 }
432 sslerr = SSL_get_error(stream->ssl, res);
433 switch (sslerr) {
434 case SSL_ERROR_ZERO_RETURN:
435 ast_debug(1, "TLS clean shutdown alert writing data\n");
436 if (written) {
437 /* Report partial write. */
438 return written;
439 }
440 errno = EBADF;
441 return -1;
442 case SSL_ERROR_WANT_READ:
443 ms = ast_remaining_ms(start, stream->timeout);
444 if (!ms) {
445 /* Report partial write. */
446 ast_debug(1, "TLS timeout writing data (want read)\n");
447 return written;
448 }
449 ast_wait_for_input(stream->fd, ms);
450 break;
451 case SSL_ERROR_WANT_WRITE:
452 ms = ast_remaining_ms(start, stream->timeout);
453 if (!ms) {
454 /* Report partial write. */
455 ast_debug(1, "TLS timeout writing data (want write)\n");
456 return written;
457 }
458 ast_wait_for_output(stream->fd, ms);
459 break;
460 default:
461 /* Undecoded SSL or transport error. */
462 ast_debug(1, "TLS transport or SSL error writing data: %s, %s\n", ERR_error_string(sslerr, err),
463 ssl_error_to_string(sslerr, res));
464 if (written) {
465 /* Report partial write. */
466 return written;
467 }
468 errno = EBADF;
469 return -1;
470 }
471 }
472 }
473#endif /* defined(DO_SSL) */
474
475 written = 0;
476 remaining = size;
477 for (;;) {
478 res = write(stream->fd, buffer + written, remaining);
479 if (res == remaining) {
480 /* Yay everything was written. */
481 return size;
482 }
483 if (0 < res) {
484 /* Successfully wrote part of the buffer. Try to write the rest. */
485 written += res;
486 remaining -= res;
487 continue;
488 }
489 if (errno != EINTR && errno != EAGAIN) {
490 /* Not a retryable error. */
491 ast_debug(1, "TCP socket error writing: %s\n", strerror(errno));
492 if (written) {
493 return written;
494 }
495 return -1;
496 }
497 ms = ast_remaining_ms(start, stream->timeout);
498 if (!ms) {
499 /* Report partial write. */
500 ast_debug(1, "TCP timeout writing data\n");
501 return written;
502 }
503 ast_wait_for_output(stream->fd, ms);
504 }
505}
#define ast_debug(level,...)
Log a DEBUG message.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2315
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
int ast_wait_for_output(int fd, int ms)
Definition utils.c:1742

References ast_debug, ast_remaining_ms(), ast_tvnow(), ast_wait_for_input(), ast_wait_for_output(), errno, ast_iostream::fd, ast_iostream::ssl, ast_iostream::start, and ast_iostream::timeout.

Referenced by ast_http_send(), ast_iostream_printf(), ast_websocket_write(), process_output(), send_eivr_event(), send_string(), and websocket_close().