Asterisk - The Open Source Telephony Project GIT-master-7921072
Data Structures | Functions
iostream.c File Reference
#include "asterisk.h"
#include "asterisk/iostream.h"
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "asterisk/astobj2.h"
#include "asterisk/logger.h"
#include "asterisk/strings.h"
#include "asterisk/threadstorage.h"
#include "asterisk/time.h"
#include "asterisk/utils.h"
Include dependency graph for iostream.c:

Go to the source code of this file.

Data Structures

struct  ast_iostream
 

Functions

int ast_iostream_close (struct ast_iostream *stream)
 Close an iostream. More...
 
ssize_t ast_iostream_discard (struct ast_iostream *stream, size_t size)
 Discard the specified number of bytes from an iostream. More...
 
struct ast_iostreamast_iostream_from_fd (int *fd)
 Create an iostream from a file descriptor. More...
 
int ast_iostream_get_fd (struct ast_iostream *stream)
 Get an iostream's file descriptor. More...
 
SSLast_iostream_get_ssl (struct ast_iostream *stream)
 Get a pointer to an iostream's OpenSSL SSL structure. More...
 
ssize_t ast_iostream_gets (struct ast_iostream *stream, char *buffer, size_t size)
 Read a LF-terminated string from an iostream. More...
 
void ast_iostream_nonblock (struct ast_iostream *stream)
 Make an iostream non-blocking. More...
 
ssize_t ast_iostream_printf (struct ast_iostream *stream, const char *format,...)
 Write a formatted string to an iostream. More...
 
ssize_t ast_iostream_read (struct ast_iostream *stream, void *buffer, size_t count)
 Read data from an iostream. More...
 
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. More...
 
void ast_iostream_set_timeout_disable (struct ast_iostream *stream)
 Disable the iostream timeout timer. More...
 
void ast_iostream_set_timeout_idle_inactivity (struct ast_iostream *stream, int timeout, int timeout_reset)
 Set the iostream inactivity & idle timeout timers. More...
 
void ast_iostream_set_timeout_inactivity (struct ast_iostream *stream, int timeout)
 Set the iostream inactivity timeout timer. More...
 
void ast_iostream_set_timeout_sequence (struct ast_iostream *stream, struct timeval start, int timeout)
 Set the iostream I/O sequence timeout timer. More...
 
int ast_iostream_start_tls (struct ast_iostream **pstream, SSL_CTX *ssl_ctx, int client)
 Begin TLS on an iostream. More...
 
int ast_iostream_wait_for_input (struct ast_iostream *stream, int timeout)
 Wait for input on the iostream's file descriptor. More...
 
ssize_t ast_iostream_write (struct ast_iostream *stream, const void *buffer, size_t size)
 Write data to an iostream. More...
 
static void iostream_dtor (void *cookie)
 
static ssize_t iostream_read (struct ast_iostream *stream, void *buf, size_t size)
 

Function Documentation

◆ 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 528 of file iostream.c.

529{
530 if (!stream) {
531 errno = EBADF;
532 return -1;
533 }
534
535 if (stream->fd != -1) {
536#if defined(DO_SSL)
537 if (stream->ssl) {
538 int res;
539
540 /*
541 * According to the TLS standard, it is acceptable for an
542 * application to only send its shutdown alert and then
543 * close the underlying connection without waiting for
544 * the peer's response (this way resources can be saved,
545 * as the process can already terminate or serve another
546 * connection).
547 */
548 res = SSL_shutdown(stream->ssl);
549 if (res < 0) {
550 int sslerr = SSL_get_error(stream->ssl, res);
551 char err[256];
552 ast_log(LOG_ERROR, "SSL_shutdown() failed: %s, %s\n",
553 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
554 }
555
556#if !(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000L)) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
557 if (!SSL_is_server(stream->ssl)) {
558#else
559 if (!stream->ssl->server) {
560#endif
561 /* For client threads, ensure that the error stack is cleared */
562#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L)
563#if OPENSSL_VERSION_NUMBER >= 0x10000000L
564 ERR_remove_thread_state(NULL);
565#else
566 ERR_remove_state(0);
567#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */
568#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
569 }
570
571 SSL_free(stream->ssl);
572 stream->ssl = NULL;
573 }
574#endif /* defined(DO_SSL) */
575
576 /*
577 * Issuing shutdown() is necessary here to avoid a race
578 * condition where the last data written may not appear
579 * in the TCP stream. See ASTERISK-23548
580 */
581 shutdown(stream->fd, SHUT_RDWR);
582 if (close(stream->fd)) {
583 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
584 }
585 stream->fd = -1;
586 }
587 ao2_t_ref(stream, -1, "Closed ast_iostream");
588
589 return 0;
590}
#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(), ast_websocket_close(), auth_http_callback(), close_mansession_file(), generic_http_callback(), session_destroy_fn(), and session_instance_destructor().

◆ 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 357 of file iostream.c.

358{
359 char buf[1024];
360 size_t remaining = size;
361 ssize_t ret;
362
363 while (remaining) {
364 ret = ast_iostream_read(stream, buf, remaining > sizeof(buf) ? sizeof(buf) : remaining);
365 if (ret <= 0) {
366 return ret;
367 }
368 remaining -= ret;
369 }
370
371 return size;
372}
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:273

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 604 of file iostream.c.

605{
606 struct ast_iostream *stream;
607
608 stream = ao2_alloc_options(sizeof(*stream), iostream_dtor,
610 if (stream) {
611 stream->timeout = -1;
612 stream->timeout_reset = -1;
613 stream->fd = *fd;
614 *fd = -1;
615 }
616
617 return stream;
618}
@ 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:592
int timeout
Definition: iostream.c:43
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 84 of file iostream.c.

85{
86 return stream->fd;
87}

References ast_iostream::fd.

Referenced by action_waitevent(), 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(), and session_do().

◆ 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 108 of file iostream.c.

109{
110 return stream->ssl;
111}

References ast_iostream::ssl.

Referenced by ast_websocket_uri_cb(), handle_tcptls_connection(), 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 300 of file iostream.c.

301{
302 size_t remaining = size;
303 ssize_t accum_size = 0;
304 ssize_t len;
305 char *newline;
306
307 for (;;) {
308 /* Search for newline */
309 newline = memchr(stream->rbufhead, '\n', stream->rbuflen);
310 if (newline) {
311 len = newline - stream->rbufhead + 1;
312 if (len > remaining - 1) {
313 len = remaining - 1;
314 }
315 break;
316 }
317
318 /* Enough buffered line data to fill request buffer? */
319 if (stream->rbuflen >= remaining - 1) {
320 len = remaining - 1;
321 break;
322 }
323 if (stream->rbuflen) {
324 /* Put leftover buffered line data into request buffer */
325 memcpy(buffer + accum_size, stream->rbufhead, stream->rbuflen);
326 remaining -= stream->rbuflen;
327 accum_size += stream->rbuflen;
328 stream->rbuflen = 0;
329 }
330 stream->rbufhead = stream->rbuf;
331
332 len = iostream_read(stream, stream->rbuf, sizeof(stream->rbuf));
333 if (len == 0) {
334 /* Nothing new was read. Return whatever we have accumulated. */
335 break;
336 }
337 if (len < 0) {
338 if (accum_size) {
339 /* We have an accumulated buffer so return that instead. */
340 len = 0;
341 break;
342 }
343 return len;
344 }
345 stream->rbuflen += len;
346 }
347
348 /* Return read buffer string length */
349 memcpy(buffer + accum_size, stream->rbufhead, len);
350 buffer[accum_size + len] = 0;
351 stream->rbuflen -= len;
352 stream->rbufhead += len;
353
354 return accum_size + len;
355}
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:155
int rbuflen
Definition: iostream.c:46
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 103 of file iostream.c.

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

References ast_fd_set_flags, and ast_iostream::fd.

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

◆ 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 491 of file iostream.c.

492{
493 char sbuf[512], *buf = sbuf;
494 int len, len2, ret = -1;
495 va_list va;
496
497 va_start(va, format);
498 len = vsnprintf(buf, sizeof(sbuf), format, va);
499 va_end(va);
500
501 if (len > sizeof(sbuf) - 1) {
502 /* Add one to the string length to accommodate the NULL byte */
503 size_t buf_len = len + 1;
504
505 buf = ast_malloc(buf_len);
506 if (!buf) {
507 return -1;
508 }
509 va_start(va, format);
510 len2 = vsnprintf(buf, buf_len, format, va);
511 va_end(va);
512 if (len2 != len) {
513 goto error;
514 }
515 }
516
517 if (ast_iostream_write(stream, buf, len) == len)
518 ret = len;
519
520error:
521 if (buf != sbuf) {
522 ast_free(buf);
523 }
524
525 return ret;
526}
#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:374
int error(const char *format,...)
Definition: utils/frame.c:999

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

Referenced by ast_http_send(), ast_websocket_uri_cb(), and websocket_client_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 273 of file iostream.c.

274{
275 if (!count) {
276 /* You asked for no data you got no data. */
277 return 0;
278 }
279
280 if (!stream || stream->fd == -1) {
281 errno = EBADF;
282 return -1;
283 }
284
285 /* Get any remains from the read buffer */
286 if (stream->rbuflen) {
287 size_t r = count;
288 if (r > stream->rbuflen) {
289 r = stream->rbuflen;
290 }
291 memcpy(buffer, stream->rbufhead, r);
292 stream->rbuflen -= r;
293 stream->rbufhead += r;
294 return r;
295 }
296
297 return iostream_read(stream, buffer, count);
298}

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 148 of file iostream.c.

149{
150 ast_assert(stream != NULL);
151
152 stream->exclusive_input = exclusive_input;
153}
int exclusive_input
Definition: iostream.c:45
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_iostream::exclusive_input, and NULL.

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

◆ 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 113 of file iostream.c.

114{
115 ast_assert(stream != NULL);
116
117 stream->timeout = -1;
118 stream->timeout_reset = -1;
119}

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

Referenced by ast_websocket_close(), ast_websocket_write(), send_string(), and session_do().

◆ 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 130 of file iostream.c.

131{
132 ast_assert(stream != NULL);
133
134 stream->start.tv_sec = 0;
135 stream->timeout = timeout;
136 stream->timeout_reset = timeout_reset;
137}
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 121 of file iostream.c.

122{
123 ast_assert(stream != NULL);
124
125 stream->start.tv_sec = 0;
126 stream->timeout = timeout;
127 stream->timeout_reset = timeout;
128}

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

Referenced by ast_websocket_close(), and send_string().

◆ 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 139 of file iostream.c.

140{
141 ast_assert(stream != NULL);
142
143 stream->start = start;
144 stream->timeout = timeout;
145 stream->timeout_reset = timeout;
146}

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

Referenced by ast_websocket_write(), and session_do().

◆ 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 620 of file iostream.c.

621{
622#ifdef DO_SSL
623 struct ast_iostream *stream = *pstream;
624 int (*ssl_setup)(SSL *) = client ? SSL_connect : SSL_accept;
625 int res;
626
627 stream->ssl = SSL_new(ssl_ctx);
628 if (!stream->ssl) {
629 ast_log(LOG_ERROR, "Unable to create new SSL connection\n");
630 errno = ENOMEM;
631 return -1;
632 }
633
634 /*
635 * This function takes struct ast_iostream **, so it can chain
636 * SSL over any ast_iostream. For now we assume it's a file descriptor.
637 * But later this should instead use BIO wrapper to tie SSL to another
638 * ast_iostream.
639 */
640 SSL_set_fd(stream->ssl, stream->fd);
641
642 res = ssl_setup(stream->ssl);
643 if (res <= 0) {
644 int sslerr = SSL_get_error(stream->ssl, res);
645 char err[256];
646
647 ast_log(LOG_ERROR, "Problem setting up ssl connection: %s, %s\n",
648 ERR_error_string(sslerr, err), ssl_error_to_string(sslerr, res));
649 errno = EIO;
650 return -1;
651 }
652
653 return 0;
654#else
655 ast_log(LOG_ERROR, "SSL not enabled in this build\n");
656 errno = ENOTSUP;
657 return -1;
658#endif
659}
struct ssl_st SSL
Definition: iostream.h:37

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

Referenced by handle_tcptls_connection().

◆ 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 89 of file iostream.c.

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

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 374 of file iostream.c.

375{
376 struct timeval start;
377 int ms;
378 int res;
379 int written;
380 int remaining;
381
382 if (!size) {
383 /* You asked to write no data you wrote no data. */
384 return 0;
385 }
386
387 if (!stream || stream->fd == -1) {
388 errno = EBADF;
389 return -1;
390 }
391
392 if (stream->start.tv_sec) {
393 start = stream->start;
394 } else {
395 start = ast_tvnow();
396 }
397
398#if defined(DO_SSL)
399 if (stream->ssl) {
400 written = 0;
401 remaining = size;
402 for (;;) {
403 int sslerr;
404 char err[256];
405 res = SSL_write(stream->ssl, buffer + written, remaining);
406 if (res == remaining) {
407 /* Everything was written. */
408 return size;
409 }
410 if (0 < res) {
411 /* Successfully wrote part of the buffer. Try to write the rest. */
412 written += res;
413 remaining -= res;
414 continue;
415 }
416 sslerr = SSL_get_error(stream->ssl, res);
417 switch (sslerr) {
418 case SSL_ERROR_ZERO_RETURN:
419 ast_debug(1, "TLS clean shutdown alert writing data\n");
420 if (written) {
421 /* Report partial write. */
422 return written;
423 }
424 errno = EBADF;
425 return -1;
426 case SSL_ERROR_WANT_READ:
427 ms = ast_remaining_ms(start, stream->timeout);
428 if (!ms) {
429 /* Report partial write. */
430 ast_debug(1, "TLS timeout writing data (want read)\n");
431 return written;
432 }
433 ast_wait_for_input(stream->fd, ms);
434 break;
435 case SSL_ERROR_WANT_WRITE:
436 ms = ast_remaining_ms(start, stream->timeout);
437 if (!ms) {
438 /* Report partial write. */
439 ast_debug(1, "TLS timeout writing data (want write)\n");
440 return written;
441 }
442 ast_wait_for_output(stream->fd, ms);
443 break;
444 default:
445 /* Undecoded SSL or transport error. */
446 ast_debug(1, "TLS transport or SSL error writing data: %s, %s\n", ERR_error_string(sslerr, err),
447 ssl_error_to_string(sslerr, res));
448 if (written) {
449 /* Report partial write. */
450 return written;
451 }
452 errno = EBADF;
453 return -1;
454 }
455 }
456 }
457#endif /* defined(DO_SSL) */
458
459 written = 0;
460 remaining = size;
461 for (;;) {
462 res = write(stream->fd, buffer + written, remaining);
463 if (res == remaining) {
464 /* Yay everything was written. */
465 return size;
466 }
467 if (0 < res) {
468 /* Successfully wrote part of the buffer. Try to write the rest. */
469 written += res;
470 remaining -= res;
471 continue;
472 }
473 if (errno != EINTR && errno != EAGAIN) {
474 /* Not a retryable error. */
475 ast_debug(1, "TCP socket error writing: %s\n", strerror(errno));
476 if (written) {
477 return written;
478 }
479 return -1;
480 }
481 ms = ast_remaining_ms(start, stream->timeout);
482 if (!ms) {
483 /* Report partial write. */
484 ast_debug(1, "TCP timeout writing data\n");
485 return written;
486 }
487 ast_wait_for_output(stream->fd, ms);
488 }
489}
#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:2281
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:1708

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_close(), ast_websocket_write(), process_output(), send_eivr_event(), and send_string().

◆ iostream_dtor()

static void iostream_dtor ( void *  cookie)
static

Definition at line 592 of file iostream.c.

593{
594#ifdef AST_DEVMODE
595 /* Since the ast_assert below is the only one using stream,
596 * and ast_assert is only available with AST_DEVMODE, we
597 * put this in a conditional to avoid compiler warnings. */
598 struct ast_iostream *stream = cookie;
599#endif
600
601 ast_assert(stream->fd == -1);
602}

References ast_assert, and ast_iostream::fd.

Referenced by ast_iostream_from_fd().

◆ iostream_read()

static ssize_t iostream_read ( struct ast_iostream stream,
void *  buf,
size_t  size 
)
static

Definition at line 155 of file iostream.c.

156{
157 struct timeval start;
158 int ms;
159 int res;
160
161 if (stream->start.tv_sec) {
162 start = stream->start;
163 } else {
164 start = ast_tvnow();
165 }
166
167#if defined(DO_SSL)
168 if (stream->ssl) {
169 for (;;) {
170 int sslerr;
171 char err[256];
172 res = SSL_read(stream->ssl, buf, size);
173 if (0 < res) {
174 /* We read some payload data. */
175 stream->timeout = stream->timeout_reset;
176 return res;
177 }
178 sslerr = SSL_get_error(stream->ssl, res);
179 switch (sslerr) {
180 case SSL_ERROR_ZERO_RETURN:
181 /* Report EOF for a shutdown */
182 ast_debug(1, "TLS clean shutdown alert reading data\n");
183 return 0;
184 case SSL_ERROR_WANT_READ:
185 if (!stream->exclusive_input) {
186 /* We cannot wait for data now. */
187 errno = EAGAIN;
188 return -1;
189 }
190 while ((ms = ast_remaining_ms(start, stream->timeout))) {
191 res = ast_wait_for_input(stream->fd, ms);
192 if (0 < res) {
193 /* Socket is ready to be read. */
194 break;
195 }
196 if (res < 0) {
197 if (errno == EINTR || errno == EAGAIN) {
198 /* Try again. */
199 continue;
200 }
201 ast_debug(1, "TLS socket error waiting for read data: %s\n",
202 strerror(errno));
203 return -1;
204 }
205 }
206 break;
207 case SSL_ERROR_WANT_WRITE:
208 while ((ms = ast_remaining_ms(start, stream->timeout))) {
209 res = ast_wait_for_output(stream->fd, ms);
210 if (0 < res) {
211 /* Socket is ready to be written. */
212 break;
213 }
214 if (res < 0) {
215 if (errno == EINTR || errno == EAGAIN) {
216 /* Try again. */
217 continue;
218 }
219 ast_debug(1, "TLS socket error waiting for write space: %s\n",
220 strerror(errno));
221 return -1;
222 }
223 }
224 break;
225 case SSL_ERROR_SYSCALL:
226 /* Some non-recoverable I/O error occurred. The OpenSSL error queue may
227 * contain more information on the error. For socket I/O on Unix systems,
228 * consult errno for details. */
229 ast_debug(1, "TLS non-recoverable I/O error occurred: %s, %s\n", ERR_error_string(sslerr, err),
230 ssl_error_to_string(sslerr, res));
231 return -1;
232 default:
233 /* Report EOF for an undecoded SSL or transport error. */
234 ast_debug(1, "TLS transport or SSL error reading data: %s, %s\n", ERR_error_string(sslerr, err),
235 ssl_error_to_string(sslerr, res));
236 return -1;
237 }
238 if (!ms) {
239 /* Report EOF for a timeout */
240 ast_debug(1, "TLS timeout reading data\n");
241 return 0;
242 }
243 }
244 }
245#endif /* defined(DO_SSL) */
246
247 for (;;) {
248 res = read(stream->fd, buf, size);
249 if (0 <= res) {
250 /* Got data or we cannot wait for it. */
251 stream->timeout = stream->timeout_reset;
252 return res;
253 }
254 if (!stream->exclusive_input) {
255 return res;
256 }
257 if (errno != EINTR && errno != EAGAIN) {
258 /* Not a retryable error. */
259 ast_debug(1, "TCP socket error reading data: %s\n",
260 strerror(errno));
261 return -1;
262 }
263 ms = ast_remaining_ms(start, stream->timeout);
264 if (!ms) {
265 /* Report EOF for a timeout */
266 ast_debug(1, "TCP timeout reading data\n");
267 return 0;
268 }
269 ast_wait_for_input(stream->fd, ms);
270 }
271}

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

Referenced by ast_iostream_gets(), and ast_iostream_read().